ONT 16S Sequencing Files

Raw fast5 files from each Oxford Nanopore (ONT) sequencing batch can be found within the directory named: raw_fast5_files/

A total of 8 sequencing batches were run. Each batch includes 24 samples from the following treatment and donor ids:
      1. UT1, UT2, UT3
      2. UT4, UT5, UT6
      3. PLA1, PLA2, PLA3
      4. PLA4, PLA5, PLA6 *NOTE: These samples had to be re-run so they represent two separate sequencing runs
      5. T1-1, T1-2, T1-3
      6. T1-4, T1-5, T1-6
      7. T2-1, T2-2, T2-3
      8. T2-4, T2-5, T2-6
So for example, the raw fast5 files of samples within UT1, UT2, UT3 would be in: raw_fast5_files/UT1_UT2_UT3_fast5s/

ONT 16S Sequence QC Pipeline

After ONT sequencing the following pipeline was used to demultiplex and quality filter reads:
1. Basecall with Dorado V 0.4.1 https://github.com/nanoporetech/dorado
3. Read quality filtering and trimming with Chopper V 0.6.0 https://github.com/wdecoster/chopper
   Trimmed fastq files can be found in the directory named: trimmed_fastqs
      Chopper parameters used:
          • Min q score: 10
          • Min length: 1,000 bp
          • Head crop: 50
          • Max length: 1690
4. Multiqc results summary using fastp qc V 0.20.1
   Multiqc results for each sequencing batch can be found in the directory named: multiqc
Full pipeline with code is available at: https://github.com/MessyaszA/ONT_demux

Taxonomic Classification

Quality filtered and trimmed reads were then aligned to the HOMD database and biom files were created for import into phyloseq.

o First, built a Kraken2 database of the 16S HOMD sequences (https://www.homd.org/ftp/16S_rRNA_refseq/HOMD_16S_rRNA_RefSeq/current/HOMD_16S_rRNA_RefSeq_V15.23.fasta)

1. Taxonomically classified reads via Kraken2 to the built HOMD 16S database
2. Estimated abundance of taxa via Bracken https://ccb.jhu.edu/software/bracken/
      Krona graphs of the Bracken abundance estimates for each sample can be found in the directory named: krona_bracken
3. Exported Bracken results as a biom file for import into phlyoseq (via taxpasta V 0.6.1 https://taxpasta.readthedocs.io/en/latest/)
Full pipeline with code for these 3 steps is available at: https://github.com/MessyaszA/bracken_taxpasta

Statistical Analysis

Diversity, differential abundance, and relative abundance of taxa were analyzed via Phyloseq and statistical tests were run between the 4 treatments.

The biom file and metadata table imported into phyloseq can be found in the directory named: stats_analysis

Results include:

o Alpha diversity metrics - Observed, Shannon, Simpson (csv tables in stats_analysis directory)
o Alpha diversity statistical tests (results below)
o Alpha diversity boxplots (tiff images in stats_analysis/alpha_diversity_plots directory)
      • *NOTE: Observed richness was run on raw and normalized data. Rarefaction to lowest read number was used as normalization.
      This was included for comparative purposes. Other normalization methods can also be run if requested.
o Pairwise differential abundance test via DeSeq2 (csv table results in stats_analysis/DESEQ2 directory)
      • Volcano plot (tiff image in stats_analysis/DESEQ2 directory)
      • *NOTE: Another differential abundance method for microbiome data (ANCOM-BC
      https://www.bioconductor.org/packages/release/bioc/html/ANCOMBC.html ) can be run if requested.
o Beta diversity statistical tests - Bray-Curtis, Euclidean distances
      • *NOTE: Methods for normalizing beta diversity metrics (i.e. calculating Aitchison distance via the deicode package in Qiime2
      https://library.qiime2.org/plugins/deicode/19/) can be run if requested.
o Beta diversity plots (tiff images in stats_analysis/beta_diversity_plots directory)
o Relative abundance taxa plots (tiff images can be found in stats_analysis/taxaplots directory)

#Libraries we will use
library("DESeq2")
library("ggplot2")
library(Biostrings)
library("phyloseq")
library("microbiome")
library("ggthemes")
library(ggnetwork)
library(cowplot)
library("vegan")
library(magrittr)
library(dplyr)
library(EnhancedVolcano)

#Create a few output directories that will hold the output files. 
dir.create('./DESEQ2')
dir.create('./ANCOM')
# Load data and add metadata
ps_object <- import_biom("./HOMD_biom_merge.biom")

#import medata and add to phyloseq object
metadata <- read.csv("./metadata.csv", row.names = 1)
metadata = sample_data(data.frame(metadata))
sample_data(ps_object) <- metadata

Statistical Analysis Results

Total number of taxa

The total number of taxonomically identified ASVs across all samples

#Check sample numbers
ntaxa(ps_object) #Total taxa
[1] 535

Number of taxonomically classified reads per sample

Samples will have varying numbers of taxonomically classified reads due to different sampling depths during sequencing.

#Check sample numbers
sample_sums(ps_object) #Reads per sample
PLA-6G.trim.fastq_bracken PLA-5F.trim.fastq_bracken PLA-6D.trim.fastq_bracken PLA-6E.trim.fastq_bracken 
                   122253                    134537                    151338                    160823 
PLA-4G.trim.fastq_bracken  T1-6D.trim.fastq_bracken PLA-5H.trim.fastq_bracken PLA-6F.trim.fastq_bracken 
                   134896                    252097                    164959                    111641 
 T1-6E.trim.fastq_bracken PLA-4F.trim.fastq_bracken  T1-5E.trim.fastq_bracken PLA-4D.trim.fastq_bracken 
                   218460                    261085                    327649                    193079 
 T1-5F.trim.fastq_bracken  T1-5D.trim.fastq_bracken  T1-4A.trim.fastq_bracken PLA-5A.trim.fastq_bracken 
                   269287                    296705                    332687                    141418 
PLA-5G.trim.fastq_bracken  T1-6H.trim.fastq_bracken PLA-5B.trim.fastq_bracken  T1-5G.trim.fastq_bracken 
                   244555                    219936                    271721                    281291 
PLA-6B.trim.fastq_bracken  T1-6G.trim.fastq_bracken PLA-4C.trim.fastq_bracken PLA-4A.trim.fastq_bracken 
                   196991                    217395                    308241                    314998 
 T1-4H.trim.fastq_bracken  T1-6F.trim.fastq_bracken  T1-6A.trim.fastq_bracken  T1-4B.trim.fastq_bracken 
                   276626                    205810                    229874                    340421 
 T1-5H.trim.fastq_bracken PLA-4E.trim.fastq_bracken  T1-6C.trim.fastq_bracken  T1-5C.trim.fastq_bracken 
                   307412                    185855                    202763                    291410 
PLA-6H.trim.fastq_bracken  T2-4A.trim.fastq_bracken  T2-6F.trim.fastq_bracken  T2-5D.trim.fastq_bracken 
                   124695                    177019                    121162                    149516 
PLA-5C.trim.fastq_bracken  T1-4G.trim.fastq_bracken  T2-4C.trim.fastq_bracken  T2-4B.trim.fastq_bracken 
                   115282                    229188                    175811                    166040 
 T2-5A.trim.fastq_bracken PLA-6C.trim.fastq_bracken PLA-5D.trim.fastq_bracken PLA-5E.trim.fastq_bracken 
                   143238                    149583                    148025                    147511 
 T2-4G.trim.fastq_bracken PLA-4B.trim.fastq_bracken  T1-6B.trim.fastq_bracken  T2-5E.trim.fastq_bracken 
                   122305                    307852                    233657                    230137 
 T2-5C.trim.fastq_bracken  T2-4F.trim.fastq_bracken  T2-6H.trim.fastq_bracken  T2-6E.trim.fastq_bracken 
                   135595                    136812                    122927                    114585 
 T2-6G.trim.fastq_bracken PLA-4H.trim.fastq_bracken  T2-5F.trim.fastq_bracken  T2-6C.trim.fastq_bracken 
                   111199                    232902                    117429                     99830 
 T2-6A.trim.fastq_bracken  T2-4H.trim.fastq_bracken  T2-5G.trim.fastq_bracken  T1-1E.trim.fastq_bracken 
                   134098                    139078                    141449                    129593 
 T1-4F.trim.fastq_bracken  T2-4E.trim.fastq_bracken  T2-6D.trim.fastq_bracken  T2-5B.trim.fastq_bracken 
                   291101                    158881                    111618                    156670 
 T2-5H.trim.fastq_bracken  T1-4E.trim.fastq_bracken  T1-5A.trim.fastq_bracken  T1-5B.trim.fastq_bracken 
                   146811                    320326                    295293                    335887 
 T1-2C.trim.fastq_bracken PLA-2A.trim.fastq_bracken  T1-1H.trim.fastq_bracken  T1-2F.trim.fastq_bracken 
                   112517                    129688                    112481                    111566 
 T1-3D.trim.fastq_bracken  T1-1A.trim.fastq_bracken  T1-1D.trim.fastq_bracken  T1-1B.trim.fastq_bracken 
                   137279                    156574                    156381                    142894 
 T1-3B.trim.fastq_bracken  T1-3E.trim.fastq_bracken  T1-3F.trim.fastq_bracken  T1-2E.trim.fastq_bracken 
                   143554                    136304                    126753                    137682 
 T1-2G.trim.fastq_bracken  T1-2D.trim.fastq_bracken  T2-6B.trim.fastq_bracken PLA-6A.trim.fastq_bracken 
                   138687                    135530                    107692                    221393 
 T2-4D.trim.fastq_bracken  T1-4D.trim.fastq_bracken  T1-4C.trim.fastq_bracken  T1-1G.trim.fastq_bracken 
                   186787                    516674                    347729                     97588 
 T1-2H.trim.fastq_bracken  T1-1F.trim.fastq_bracken  T1-2B.trim.fastq_bracken  T1-1C.trim.fastq_bracken 
                   132909                    100480                    169725                    150087 
 T1-3G.trim.fastq_bracken  T1-3H.trim.fastq_bracken  T1-2A.trim.fastq_bracken  T1-3C.trim.fastq_bracken 
                   132758                    137643                    121393                    134268 
PLA-1H.trim.fastq_bracken  T1-3A.trim.fastq_bracken PLA-1A.trim.fastq_bracken PLA-1C.trim.fastq_bracken 
                   113231                    164631                    150169                    136540 
PLA-3D.trim.fastq_bracken PLA-3C.trim.fastq_bracken PLA-3A.trim.fastq_bracken PLA-3E.trim.fastq_bracken 
                   128055                    127764                    152664                    137933 
PLA-3H.trim.fastq_bracken PLA-1G.trim.fastq_bracken  UT-5C.trim.fastq_bracken PLA-2F.trim.fastq_bracken 
                   139049                    113533                    142315                    116570 
PLA-2D.trim.fastq_bracken PLA-2C.trim.fastq_bracken PLA-3B.trim.fastq_bracken PLA-2E.trim.fastq_bracken 
                   119736                    124253                    121101                    141694 
PLA-1E.trim.fastq_bracken PLA-2H.trim.fastq_bracken PLA-3G.trim.fastq_bracken PLA-1B.trim.fastq_bracken 
                   139254                    124653                    134659                    139846 
PLA-2G.trim.fastq_bracken PLA-3F.trim.fastq_bracken  UT-6B.trim.fastq_bracken  UT-6G.trim.fastq_bracken 
                   131090                    124131                    149386                    157610 
 UT-4B.trim.fastq_bracken  UT-5E.trim.fastq_bracken PLA-2B.trim.fastq_bracken  UT-4A.trim.fastq_bracken 
                   188401                    204864                    147226                    232458 
 UT-4D.trim.fastq_bracken PLA-1D.trim.fastq_bracken  UT-4G.trim.fastq_bracken PLA-1F.trim.fastq_bracken 
                   230691                    170659                    146773                    114481 
 UT-4E.trim.fastq_bracken  UT-6E.trim.fastq_bracken  UT-6F.trim.fastq_bracken  UT-5D.trim.fastq_bracken 
                   180292                    160952                    150999                    161566 
 UT-5F.trim.fastq_bracken  UT-5B.trim.fastq_bracken  UT-6C.trim.fastq_bracken  UT-4H.trim.fastq_bracken 
                   162768                    194116                    137967                    148853 
 UT-5G.trim.fastq_bracken  UT-5A.trim.fastq_bracken  UT-4C.trim.fastq_bracken  UT-4F.trim.fastq_bracken 
                   155111                    166610                    210096                    174867 
 UT-5H.trim.fastq_bracken  UT-6H.trim.fastq_bracken  T2-2C.trim.fastq_bracken  T2-2H.trim.fastq_bracken 
                   171615                    155942                    224131                    236759 
 T2-1F.trim.fastq_bracken  T2-3D.trim.fastq_bracken  UT-6A.trim.fastq_bracken  UT-6D.trim.fastq_bracken 
                   220654                    226536                    150983                    154152 
 T2-2D.trim.fastq_bracken  T2-1G.trim.fastq_bracken  T2-1D.trim.fastq_bracken  T2-3G.trim.fastq_bracken 
                   212920                    196370                    254486                    241081 
 T2-3C.trim.fastq_bracken  T2-1C.trim.fastq_bracken  T2-2B.trim.fastq_bracken  T2-1B.trim.fastq_bracken 
                   244282                    288104                    247158                    265356 
 T2-3A.trim.fastq_bracken  T2-3F.trim.fastq_bracken  T2-2E.trim.fastq_bracken   UT3D.trim.fastq_bracken 
                   254775                    249430                    228892                    193130 
 T2-3B.trim.fastq_bracken  T2-2G.trim.fastq_bracken  T2-3E.trim.fastq_bracken  T2-1A.trim.fastq_bracken 
                   258304                    236985                    230370                    239366 
 T2-2F.trim.fastq_bracken  T2-1E.trim.fastq_bracken  T2-1H.trim.fastq_bracken  T2-2A.trim.fastq_bracken 
                   197203                    251642                    212102                    219040 
  UT3B.trim.fastq_bracken   UT2C.trim.fastq_bracken   UT2B.trim.fastq_bracken   UT1E.trim.fastq_bracken 
                   303307                    119023                     90053                     95039 
  UT1H.trim.fastq_bracken   UT2A.trim.fastq_bracken  T2-3H.trim.fastq_bracken   UT1F.trim.fastq_bracken 
                    85347                     94188                    246493                    103031 
  UT1G.trim.fastq_bracken   UT1B.trim.fastq_bracken   UT2H.trim.fastq_bracken   UT1A.trim.fastq_bracken 
                    90941                    251468                    131175                    215807 
  UT2E.trim.fastq_bracken   UT3C.trim.fastq_bracken   UT2G.trim.fastq_bracken   UT3G.trim.fastq_bracken 
                   174982                    159762                    230766                    293498 
  UT1D.trim.fastq_bracken   UT2F.trim.fastq_bracken   UT3H.trim.fastq_bracken   UT3E.trim.fastq_bracken 
                   146254                    257994                    263981                    195541 
  UT2D.trim.fastq_bracken   UT3F.trim.fastq_bracken   UT3A.trim.fastq_bracken   UT1C.trim.fastq_bracken 
                   255864                    276688                    284484                    290816 

Alpha Diversity

Measuring species diversity within each sample.

#Function to calculate the mean and the standard deviation for each group.
#data : a data frame
#varname : the name of a column containing the variable to be summarized
#groupnames : vector of column names to be used as grouping variables

# Calculate standard error
sderr <- function(x) {sd(x)/sqrt(length(x))}

data_summary <- function(data, varname, groupnames){
  require(plyr)
  summary_func <- function(x, col){
    c(mean = mean(x[[col]], na.rm=TRUE),
      sd = sderr(x[[col]]), na.rm=TRUE)
  }
  data_sum<-ddply(data, groupnames, .fun=summary_func,
                  varname)
  data_sum <- rename(data_sum, c("mean" = varname))
  return(data_sum)
}

Data table with alpha diversity metrics: Observed, Shannon, Simpson

Example of data table structure (full table saved as csv)

Three alpha diversity metrics are calculated for each sample. The full table (per_sample_ad_dataframe.csv) can be found in the directory named: stats_analysis

alpha_div <- cbind(estimate_richness(ps_object, 
                                                   measures = c('Observed', 'Shannon', 'Simpson')),
                                 sample_data(ps_object))
colnames(alpha_div) <- c('Observed', 'Shannon', 'Simpson')
alpha_div$Labels <- rownames(alpha_div)
ad_df <- alpha_div[,c('Observed', 'Shannon', 'Simpson')]
ad_df <- cbind(ad_df,
                              sample_data(ps_object)[, c('sample', 'group', 'donor', 'treatment')])
colnames(ad_df) <- c('Observed', 'Shannon', 'Simpson', 'sample', 'group', 'donor', 'treatment')
head(ad_df)
write.csv(ad_df, "./per_sample_ad_dataframe.csv")

Data Summary statistics: Observed, Shannon, Simpson

Summary for each treatment

The average of each alpha diversity metric for all samples within a treatment.

# Observed
data_summary(ad_df, varname = "Observed", groupnames = c("treatment"))
#data_summary(ad_df, varname = "Observed", groupnames = c("sample"))
#data_summary(ad_df, varname = "Observed", groupnames = c("donor"))

# Shannon
data_summary(ad_df, varname = "Shannon", groupnames = c("treatment"))
#data_summary(ad_df, varname = "Shannon", groupnames = c("sample"))
#data_summary(ad_df, varname = "Shannon", groupnames = c("donor"))

# Simpson
data_summary(ad_df, varname = "Simpson", groupnames = c("treatment"))
#data_summary(ad_df, varname = "Simpson", groupnames = c("sample"))
#data_summary(ad_df, varname = "Simpson", groupnames = c("donor"))

Alpha diversity statistical tests for significance

Kruskal Wallis and Pairwise Wilcoxon tests

Kruskal-Wallis Rank Sum Test for a category (treatment) on each Alpha Diversity metric calculated. This is a non-parametric method which ranks the data and tests whether samples from each group analyzed come from the same distribution.

Pairwise Wilcoxon Rank Sum Test between groups within a category (treatment) on each Alpha Diversity metric calculated and corrected for multiple testing. This methods compares two independent samples for all group levels and includes the false discovery rate (FDR) multiple test correction. The results below come up as a matrix filled with the p-values for each treatment comparison.

Observed Richness

Testing ASV/species richness between the 4 treatments.

#### Observed
#Kruskal Wallis tests
kruskal.test(Observed ~ treatment, data = ad_df)

    Kruskal-Wallis rank sum test

data:  Observed by treatment
Kruskal-Wallis chi-squared = 11.944, df = 3, p-value = 0.007577
#kruskal.test(Observed ~ sample, data = ad_df)
#kruskal.test(Observed ~ donor, data = ad_df)

#Pairwise Wilcoxon Test
pairwise.wilcox.test(ad_df$Observed, ad_df$treatment, p.adjust.method = 'fdr')

    Pairwise comparisons using Wilcoxon rank sum test with continuity correction 

data:  ad_df$Observed and ad_df$treatment 

          1.5R  8R    Placebo
8R        0.849 -     -      
Placebo   0.179 0.257 -      
Untreated 0.179 0.011 0.011  

P value adjustment method: fdr 

Shannon Diversity

Testing ASV/species richness between the 4 treatments while also taking into account relative abundance (evenness).

#### Shannon
#Kruskal Wallis tests
kruskal.test(Shannon ~ treatment, data = ad_df)

    Kruskal-Wallis rank sum test

data:  Shannon by treatment
Kruskal-Wallis chi-squared = 6.9716, df = 3, p-value = 0.07281
#kruskal.test(Shannon ~ sample, data = ad_df)
#kruskal.test(Shannon ~ donor, data = ad_df)

#Pairwise Wilcoxon Test
pairwise.wilcox.test(ad_df$Shannon, ad_df$treatment, p.adjust.method = 'fdr')

    Pairwise comparisons using Wilcoxon rank sum exact test 

data:  ad_df$Shannon and ad_df$treatment 

          1.5R 8R   Placebo
8R        0.73 -    -      
Placebo   0.92 0.64 -      
Untreated 0.11 0.17 0.10   

P value adjustment method: fdr 

Simpson Diversity

Testing ASV/species richness between the 4 treatments while also taking into account relative abundance (evenness). Simpson diversity gives more weight to common or dominant ASVs (rare ASVs will not affect diversity).

#### Simpson
#Kruskal Wallis tests
kruskal.test(Simpson ~ treatment, data = ad_df)

    Kruskal-Wallis rank sum test

data:  Simpson by treatment
Kruskal-Wallis chi-squared = 3.2214, df = 3, p-value = 0.3587
#kruskal.test(Simpson ~ sample, data = ad_df)
#kruskal.test(Simpson ~ donor, data = ad_df)

#Pairwise Wilcoxon Test
pairwise.wilcox.test(ad_df$Simpson, ad_df$treatment, p.adjust.method = 'fdr')

    Pairwise comparisons using Wilcoxon rank sum exact test 

data:  ad_df$Simpson and ad_df$treatment 

          1.5R 8R   Placebo
8R        0.60 -    -      
Placebo   0.80 0.60 -      
Untreated 0.60 0.60 0.48   

P value adjustment method: fdr 

Alpha diversity boxplots

Images of each plot can be found in: stats_analysis/alpha_diversity_plots

###Group plots
#Observed
obs_ad_plot <- ggplot(ad_df, aes(x=treatment, y=Observed, color = treatment)) + geom_boxplot() + geom_point() + ylab('Observed Richness') + scale_colour_manual(values = c("#954535", "#702963", "#F28C28", "#088F8F"))

obs_ad_plot


ggsave("obs_ad_plot.tiff", dpi = 300, plot = obs_ad_plot, path = "./alpha_diversity_plots/")

#Shannon
shan_ad_plot <- ggplot(ad_df, aes(x=treatment, y=Shannon, color = treatment)) + geom_boxplot() + geom_point() + ylab('Shannon Diversity') + scale_colour_manual(values = c("#954535", "#702963", "#F28C28", "#088F8F"))

shan_ad_plot


ggsave("shan_ad_plot.tiff", dpi = 300, plot = shan_ad_plot, path = "./alpha_diversity_plots/")

#Simpson
simp_ad_plot <- ggplot(ad_df, aes(x=treatment, y=Simpson, color = treatment)) + geom_boxplot() + geom_point() + ylab('Simpson Diversity') + scale_colour_manual(values = c("#954535", "#702963", "#F28C28", "#088F8F"))

simp_ad_plot


ggsave("simp_ad_plot.tiff", dpi = 300, plot = simp_ad_plot, path = "./alpha_diversity_plots/")

Alpha Diversity on Rarefied Data

Normalize Observed Richness metric by rarefying to lowest sample sum number

Shannon and Simpson diversity indices are already normalized by relative abundance.

Rarefaction read depth

One method of normalization is to rarefy each sample to the minimum read depth found across all samples. The minimum read depth for all samples is:

min(sample_sums(ps_object)) #Minimum reads (used for rarefying)
[1] 85347

Example of datatable structure for rarefied data observed richness (full table saved as csv)

Observed richness is calculated for each sample now rarefied to the minimum read depth. The full table (rarefied_per_sample_ad_dataframe.csv) can be found in the directory named: stats_analysis

#Rarefy to lowest sample_sums
rare_num <- min(sample_sums(ps_object))
ps_rare <- rarefy_even_depth(ps_object, sample.size = rare_num, rngseed = 999)

#Get datatable with Observed richness for rarefied samples
alpha_div_rare <- cbind(estimate_richness(ps_rare, 
                                                   measures = c('Observed')),
                                 sample_data(ps_rare))
colnames(alpha_div_rare) <- c('Observed_rare')
alpha_div_rare$Labels <- rownames(alpha_div_rare)
ad_df_rare <- alpha_div_rare[,c('Observed_rare')]
ad_df_rare <- cbind(ad_df_rare,
                              sample_data(ps_rare)[, c('sample', 'group', 'donor', 'treatment')])
colnames(ad_df_rare) <- c('Observed_rare', 'sample', 'group', 'donor', 'treatment')
head(ad_df_rare)
write.csv(ad_df_rare, "./rarefied_per_sample_ad_dataframe.csv")

Data summary for rarefied data (observed richness)

The average observed richness for all samples within a treatment.

# Observed Rarefied data summary stats
data_summary(ad_df_rare, varname = "Observed_rare", groupnames = c("treatment"))
#data_summary(ad_df_rare, varname = "Observed_rare", groupnames = c("sample"))
#data_summary(ad_df_rare, varname = "Observed_rare", groupnames = c("donor"))

Observed richness statistical tests for rarefied data

Testing ASV/species richness between the 4 treatments.


#### Observed Rarefied
#Kruskal Wallis tests
kruskal.test(Observed_rare ~ treatment, data = ad_df_rare)

    Kruskal-Wallis rank sum test

data:  Observed_rare by treatment
Kruskal-Wallis chi-squared = 12.925, df = 3, p-value = 0.004801
#kruskal.test(Observed_rare ~ sample, data = ad_df_rare)
#kruskal.test(Observed_rare ~ donor, data = ad_df_rare)

#Pairwise Wilcoxon Test
pairwise.wilcox.test(ad_df_rare$Observed_rare, ad_df_rare$treatment, p.adjust.method = 'fdr')

    Pairwise comparisons using Wilcoxon rank sum test with continuity correction 

data:  ad_df_rare$Observed_rare and ad_df_rare$treatment 

          1.5R   8R     Placebo
8R        0.6733 -      -      
Placebo   0.3884 0.6733 -      
Untreated 0.0635 0.0066 0.0066 

P value adjustment method: fdr 

Rarefied data observed richness boxplot

Images of the plot can be found in: stats_analysis/alpha_diversity_plots

#Plots: Observed Rarefied
obs_ad_plot_rare <- ggplot(ad_df_rare, aes(x=treatment, y=Observed_rare, color = treatment)) + geom_boxplot() + geom_point() + ylab('Observed Richness Rarefied Data') + scale_colour_manual(values = c("#954535", "#702963", "#F28C28", "#088F8F"))

obs_ad_plot_rare


ggsave("rarefied_obs_ad_plot.tiff", dpi = 300, plot = obs_ad_plot_rare, path = "./alpha_diversity_plots/")

Differential Abundance Analysis

Pairwise differential abundance test between treatments via DESeq2

The package DESeq2 provides methods to test for differential abundance by use of negative binomial generalized linear models. DESeq2 uses the Wald test to take into account the dispersion model distance and negative binomial distribution we see in sequencing data. Overall this method statistically infers systematic changes between conditions, as compared to within-condition variability. It estimates dispersion and logarithmic fold changes to test which sequences/ASVs are significantly changing within the experimental design.

Additionally, a p-value correction is applied for multiple hypothesis testing. Traditionally p < 0.05 is considered significant (95% chance it is not by random chance), but when you are looking at thousands of ASVs/sequences, you’ll still end up with 5% of them significant off predicted chance. One of the best corrections to use called False-Discovery Rate correction (FDR), which is the Benjamini and Hochberg method.

Here we ran DESeq2 specifying only treatment in the experimental design. Log fold changes and adjusted p-valus (padj) for all ASVs and significant ASVs have been saved as csv tables in the stats_analysis/DESEQ2 directory (named dds_result_table.csv and sig_result_table.csv respectively).

The below plot shows the fitted curve (red line) used to calculate the final dispersion estimates (blue dots) of the input data (black dots).

#Phyloseq to Deseq2
ps_deseq = phyloseq_to_deseq2(ps_object, ~treatment)

#Run Deseq2
dds = DESeq(ps_deseq, test="Wald", fitType="local")
dds_result <- results(dds)
dds_result_table <- cbind(as(dds_result, "data.frame"), as(tax_table(ps_object)[rownames(dds_result), ], "matrix"))
write.csv(dds_result_table, "./DESEQ2/dds_result_table.csv")

#check significant results
dds_sig = dds_result[which(dds_result$padj < 0.05), ]
dds_sig_table = cbind(as(dds_sig, "data.frame"), as(tax_table(ps_object)[rownames(dds_sig), ], "matrix"))
dim(dds_sig_table)
write.csv(dds_sig_table, "./DESEQ2/sig_result_table.csv")

#Perform the variance stabilizing transformation on the data and pull the normalized hit count matrix. 
vst <- varianceStabilizingTransformation(dds)
mat <- assay(vst)

#If you have a batch designed in, regress the batch effects. 
#mat <- limma::removeBatchEffect(mat, vst$batch)
#assay(vst) <- mat

#Plot the overall dispersion of the experiment to ensure it aligns with expectations. 
plotDispEsts(dds)

Volcano plot: DeSeq2 results

Volcano plots are a great way to visualize the pairwise comparisons. Each shows the log2 fold-change (log2FC) on the x-axis and -log10(padj) on the y-axis. This should usually look akin to a Plinian eruption (hence volcano plot).

Image of the volcano plot can be found in the stats_analysis/DESEQ2/ directory

p <- EnhancedVolcano(dds_result_table,
        lab=as.character(dds_result_table$Rank9),
        title="Pairwise comparisons of taxa (species level) between treatments",
        x='log2FoldChange',
        y='padj',
        legendPosition = 'bottom',
        legendLabels=c('Not sig.','Log (base 2) FC','padj-value','padj-value & Log (base 2) FC'),
        pCutoff=0.05, 
        FCcutoff=1
        )
print(p)

ggsave("volcano_plot.tiff", dpi = 300, plot = p, path = "./DESEQ2/")

Beta Diversity

Measuring species diversity or the level or similarity/dissimilarity of species between samples.

#Pairwise Adonis function
pairwise.adonis.dm <- function(x,factors,stratum=NULL,p.adjust.m="fdr",perm=999){
  
  library(vegan)
  if(class(x) != "dist") stop("x must be a dissimilarity matrix (dist object)")
  co = as.matrix(combn(unique(factors),2))
  pairs = c()
  F.Model =c()
  R2 = c()
  p.value = c()
  
  
  
  for(elem in 1:ncol(co)){
    sub_inds <- factors %in% c(as.character(co[1,elem]),as.character(co[2,elem]))
    resp <- as.matrix(x)[sub_inds,sub_inds]
    ad = adonis2(as.dist(resp) ~
                  
                  factors[sub_inds], strata=stratum[sub_inds], permutations=perm);
    
    pairs = c(pairs,paste(co[1,elem],'vs',co[2,elem]));
    F.Model =c(F.Model,ad$F[1]);
    R2 = c(R2,ad$R2[1]);
    p.value = c(p.value,ad$`Pr(>F)`[1])
    
  }
  
  p.adjusted = p.adjust(p.value,method=p.adjust.m)
  pairw.res = data.frame(pairs,F.Model,R2,p.value,p.adjusted)
  return(pairw.res)
}
# Calculate distance matrices
ps_bc <- phyloseq::distance(ps_object, method = "bray")
ps_euc <- phyloseq::distance(ps_object, method = "euclidean")

PERMANOVAs

PERMANOVA’s with Adonis - Permutational Multivariate Analysis of Variance. This measures dissimilarity in response to one or more factors in an analysis of variance design. Dissimilarity statistics are used to measure distances between data points and test whether they are significantly different.

We run the Adonis test specifying the treatment groups in the model formula.

Bray-curtis

Bray-Curtis dissimilarity examines the abundances of ASVs that are shared between two samples, and the number of ASVs found in each. Bray-Curtis dissimilarity ranges from 0-1. If 0, the two samples share all the same ASVs; if 1, they don’t share any ASVs.

Permanova result

The value under the column labeled ‘Pr(>F)’ in the results table indicates significance (i.e. p-value)

#make a dataframe out of the sample data
sampledf <- data.frame(sample_data(ps_object))

adonis2(ps_bc ~ treatment, data = sampledf) 
Permutation test for adonis under reduced model
Terms added sequentially (first to last)
Permutation: free
Number of permutations: 999

adonis2(formula = ps_bc ~ treatment, data = sampledf)
           Df SumOfSqs      R2      F Pr(>F)  
treatment   3    1.026 0.02703 1.7409  0.062 .
Residual  188   36.936 0.97297                
Total     191   37.962 1.00000                
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Euclidean

Measures the distance between two samples in Euclidean space (the length of the line segment between them).

Permanova result

The value under the column labeled ‘Pr(>F)’ in the results table indicates significance (i.e. p-value)

adonis2(ps_euc ~ treatment, data = sampledf) 
Permutation test for adonis under reduced model
Terms added sequentially (first to last)
Permutation: free
Number of permutations: 999

adonis2(formula = ps_euc ~ treatment, data = sampledf)
           Df   SumOfSqs      R2      F Pr(>F)   
treatment   3 3.0164e+10 0.03385 2.1953  0.008 **
Residual  188 8.6105e+11 0.96615                 
Total     191 8.9121e+11 1.00000                 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Pairwise comparisons

A multi-level Adonis test using the FDR multiple test correction.

Bray-curtis pairwise result

pairwise.adonis.dm(ps_bc, sampledf$treatment, p.adjust.m = "fdr")
NA

Euclidean pairwise result

pairwise.adonis.dm(ps_euc, sampledf$treatment, p.adjust.m = "fdr") 
NA

Beta diversiy PCoA and NMDS plots

PCoA and NMDS plots are used to visualize the similarities/dissimilarities of sample points using their calculated distance/dissimilarity matrices (from the Bray-curtis and Euclidean distance measurements). Samples that are closer are more related and vice versa. PCoA plots maximize the linear correlation between samples, wherein NMDS plots maximize the rank-order correlation between samples. Additionally, in case of NMDS, data is not required to fit a normal distribution.

Images of each plot can be found in the stats_analysis/beta_diversity_plots/ directory.

Bray-curtis PCoA

# Bray-curtis
#PCOA BC
ps_bc_pcoa <- ordinate(ps_object, distance = ps_bc, "PCoA")

ps_bc_pcoa_plot <- plot_ordination(ps_object, ps_bc_pcoa, color = "treatment") + 
  geom_point(size = 3) + 
  theme_classic() +
  theme(legend.position = "bottom", legend.title = element_blank()) + 
  scale_colour_manual(values = c("#954535", "#702963", "#F28C28", "#088F8F")) +
  theme(plot.title = element_text(hjust = 0.5))
ps_bc_pcoa_plot


#save as tiff
ggsave("bray_pcoa_plot.tiff", dpi = 300, plot = ps_bc_pcoa_plot, path = "./beta_diversity_plots/")

Bray-curtis NMDS

#NMDS BC
ps_bc_nmds <- ordinate(ps_object, distance = ps_bc, "NMDS")
ps_bc_nmds_plot <- plot_ordination(ps_object, ps_bc_nmds, color = "treatment") + 
  geom_point(size = 3) + 
  theme_classic() +
  theme(legend.position = "bottom", legend.title = element_blank()) + 
  scale_colour_manual(values = c("#954535", "#702963", "#F28C28", "#088F8F")) +
  theme(plot.title = element_text(hjust = 0.5))
ps_bc_nmds_plot


#save as tiff
ggsave("bray_nmds_plot.tiff", dpi = 300, plot = ps_bc_nmds_plot, path = "./beta_diversity_plots/")

Euclidean PCoA


# Euclidean
#PCOA EUC
ps_euc_pcoa <- ordinate(ps_object, distance = ps_euc, "PCoA")

ps_euc_pcoa_plot <- plot_ordination(ps_object, ps_euc_pcoa, color = "treatment") + 
  geom_point(size = 3) + 
  theme_classic() +
  theme(legend.position = "bottom", legend.title = element_blank()) + 
  scale_colour_manual(values = c("#954535", "#702963", "#F28C28", "#088F8F")) +
  theme(plot.title = element_text(hjust = 0.5))
ps_euc_pcoa_plot


#save as tiff
ggsave("euc_pcoa_plot.tiff", dpi = 300, plot = ps_euc_pcoa_plot, path = "./beta_diversity_plots/")

Euclidean NMDS

#NMDS BC
ps_euc_nmds <- ordinate(ps_object, distance = ps_euc, "NMDS")
ps_euc_nmds_plot <- plot_ordination(ps_object, ps_euc_nmds, color = "treatment") + 
  geom_point(size = 3) + 
  theme_classic() +
  theme(legend.position = "bottom", legend.title = element_blank()) + 
  scale_colour_manual(values = c("#954535", "#702963", "#F28C28", "#088F8F")) +
  theme(plot.title = element_text(hjust = 0.5))
ps_euc_nmds_plot


#save as tiff
ggsave("euc_nmds_plot.tiff", dpi = 300, plot = ps_euc_nmds_plot, path = "./beta_diversity_plots/")

Relative Abundance Taxa Plots

Relative abundance taxa bar plots for treatment

Plots were made at the phylum, genus, and species level, comparing across the 4 treatments.

Images of each plot can be found in the stats_analysis/taxaplots/ directory.

Phylum

# transform to relative abundance
ps_rel <- transform(ps_object, "compositional")

# melt the data into a table
ps_rel_melt<- ps_rel %>%
  psmelt()

# Get phylum with mean relative abundance across all samples 
ps_rel_phylum_sum <- ps_rel_melt%>% group_by(Rank3) %>% dplyr::summarise(Aver = mean(Abundance))
names_ps_rel_phylum <- ps_rel_phylum_sum$Rank3
names_ps_rel_phylum
#Phylum Plot
taxaplot_ps_rel_phylum = ggplot(ps_rel_melt
                    , aes(x = treatment, y=Abundance)) + 
  geom_bar(stat="identity", position="fill", aes(fill = Rank3))  +
  scale_fill_manual(values=c("aquamarine4", "gold","lightpink", "firebrick","#DA5724","ivory4",
                             "orchid", "#CBD588", "#8569D5", "#D14285", "#652926","grey80",
                             "#5E738F","#D1A33D", "#8A7C64","lightgreen","aquamarine4",
                             "aquamarine2", "lightsalmon", "#CD9BCD")) +
  theme_bw() +
  ylab("Relative Abundance") + xlab("Treatment") + theme(axis.text.x = element_text(angle = 90, vjust=0.5, hjust=0))
taxaplot_ps_rel_phylum <- taxaplot_ps_rel_phylum + guides(fill=guide_legend(title="Phylum"))
taxaplot_ps_rel_phylum


ggsave("taxaplot_phylum.tiff", dpi = 300, plot = taxaplot_ps_rel_phylum, path = "./taxaplots/")

Genus

Genera with a relative abundance lower than 0.0001 were grouped together.


#Get genera with mean realtive abundance >0.0001 across all samples 
ps_rel_genus_sum <- ps_rel_melt%>% group_by(Rank7) %>% dplyr::summarise(Aver = mean(Abundance))
ps_rel_genus_sub <- ps_rel_genus_sum[which(ps_rel_genus_sum$Aver > 0.0001),]
names_ps_rel_genus <- ps_rel_genus_sub$Rank7
names_ps_rel_genus
# Replace genera with <0.001 abundance with "NA"
ps_rel_melt$Rank7[ps_rel_melt$Rank7 != "Abiotrophia" &
                           ps_rel_melt$Rank7 != "Aerococcus" &
                           ps_rel_melt$Rank7 != "Dialister" &
                           ps_rel_melt$Rank7 != "Granulicatella" &
                           ps_rel_melt$Rank7 != "Ignavibacterium" &
                           ps_rel_melt$Rank7 != "Lacticaseibacillus" &
                           ps_rel_melt$Rank7 != "Lacticaseibacillus" &
                           ps_rel_melt$Rank7 != "Lactiplantibacillus" &
                           ps_rel_melt$Rank7 != "Lactobacillus" &
                           ps_rel_melt$Rank7 != "Lancefieldella" &
                           ps_rel_melt$Rank7 != "Lentilactobacillus" &
                           ps_rel_melt$Rank7 != "Levilactobacillus" &
                           ps_rel_melt$Rank7 != "Limosilactobacillus" &
                           ps_rel_melt$Rank7 != "Megasphaera" &
                           ps_rel_melt$Rank7 != "Moryella" &
                           ps_rel_melt$Rank7 != "Shuttleworthia" &
                           ps_rel_melt$Rank7 != "Solobacterium" &
                           ps_rel_melt$Rank7 != "Staphylococcus" &
                           ps_rel_melt$Rank7 != "Streptococcus" &
                           ps_rel_melt$Rank7 != "Veillonella"] <- NA

#replace NA with "Rel. Abund.<0.0001"
ps_rel_melt[is.na(ps_rel_melt)]<-"Rel. Abund.<0.0001"
#Genera plot
taxaplot_ps_rel_genus = ggplot(ps_rel_melt
                    , aes(x = treatment, y=Abundance)) + 
  geom_bar(stat="identity", position="fill", aes(fill = Rank7))  +
  scale_fill_manual(values=c("aquamarine4", "gold","lightpink", "firebrick","#DA5724","ivory4",
                             "orchid", "#CBD588", "#8569D5", "#D14285", "#652926","grey80",
                             "#5E738F","#D1A33D", "#8A7C64","lightgreen","aquamarine4",
                             "aquamarine2", "lightsalmon", "#CD9BCD")) +
  theme_bw() +
  ylab("Relative Abundance") + xlab("Treatment") + theme(axis.text.x = element_text(angle = 90, vjust=0.5, hjust=0))
taxaplot_ps_rel_genus <- taxaplot_ps_rel_genus + guides(fill=guide_legend(title="Genus"))
taxaplot_ps_rel_genus

ggsave("taxaplot_genus.tiff", dpi = 300, plot = taxaplot_ps_rel_genus, path = "./taxaplots/")

Species

Species with a relative abundance lower than 0.01 were grouped together.

#Get species with mean realtive abundance >0.01 across all samples 
ps_rel_species_sum <- ps_rel_melt%>% group_by(Rank9) %>% dplyr::summarise(Aver = mean(Abundance))
ps_rel_species_sub <- ps_rel_species_sum[which(ps_rel_species_sum$Aver > 0.01),]
names_ps_rel_species <- ps_rel_species_sub$Rank9
names_ps_rel_species
# Replace genera with <0.001 abundance with "NA"
# Replace genera with <0.001 abundance with "NA"
ps_rel_melt$Rank9[ps_rel_melt$Rank9 != "Lactobacillus crispatus" &
                           ps_rel_melt$Rank9 != "Lactobacillus jensenii" &
                           ps_rel_melt$Rank9 != "Limosilactobacillus fermentum" &
                           ps_rel_melt$Rank9 != "Limosilactobacillus vaginalis" &
                           ps_rel_melt$Rank9 != "Megasphaera micronuciformis" &
                           ps_rel_melt$Rank9 != "Streptococcus anginosus" &
                           ps_rel_melt$Rank9 != "Streptococcus mutans" &
                           ps_rel_melt$Rank9 != "Streptococcus salivarius" &
                           ps_rel_melt$Rank9 != "Streptococcus vestibularis" &
                           ps_rel_melt$Rank9 != "Veillonella atypica" &
                           ps_rel_melt$Rank9 != "Veillonella dispar" &
                           ps_rel_melt$Rank9 != "Veillonella genomosp. P1 oral clone MB5_P17" &
                           ps_rel_melt$Rank9 != "Veillonella sp. oral taxon 158"] <- NA

#replace NA with "Rel. Abund.<0.01"
ps_rel_melt[is.na(ps_rel_melt)]<-"Rel. Abund.<0.01"
#Species plot
taxaplot_ps_rel_species = ggplot(ps_rel_melt
                    , aes(x = treatment, y=Abundance)) + 
  geom_bar(stat="identity", position="fill", aes(fill = Rank9))  +
  scale_fill_manual(values=c("aquamarine4", "gold","lightpink", "firebrick","#DA5724","ivory4",
                             "orchid", "#CBD588", "#8569D5", "#D14285", "#652926","grey80",
                             "#5E738F", "#D1A33D")) +
  theme_bw() +
  ylab("Relative Abundance") + xlab("Treatment") + theme(axis.text.x = element_text(angle = 90, vjust=0.5, hjust=0))
taxaplot_ps_rel_species <- taxaplot_ps_rel_species + guides(fill=guide_legend(title="Species"))
taxaplot_ps_rel_species

ggsave("taxaplot_species.tiff", dpi = 300, plot = taxaplot_ps_rel_species, path = "./taxaplots/")

Relative abundance top 10 taxa bar plots per sample

Plots were made at the phylum, genus, and species level, comparing across all samples.

Images of each plot can be found in the stats_analysis/taxaplots/ directory.

Top 10 Phyla

# transform to relative abundance
ps_rel <- transform(ps_object, "compositional")

#Top 10 PHYLA
#Get phylum level
ps_phylum <- tax_glom(ps_rel, taxrank= "Rank3")
#Get top 10 phylum
phylum_top10 <- names(sort(taxa_sums(ps_phylum), decreasing=TRUE))[1:10]
ps_phylum_top10 <- prune_taxa(phylum_top10, ps_phylum)

# melt the data into a table
ps_phylum_melt<- ps_phylum_top10 %>%
  psmelt()

# Plot top 10 phylum by sample
taxaplot_ps_top10_phylum = ggplot(ps_phylum_melt
                    , aes(x = sample, y=Abundance)) + 
  geom_bar(stat="identity", position="fill", aes(fill = Rank3))  +
  scale_fill_manual(values=c("aquamarine4", "gold","lightpink", "firebrick","#DA5724","ivory4",
                             "orchid", "#CBD588", "#8569D5", "#D14285")) +
  theme_bw() +
  ylab("Relative Abundance") + xlab("Sample") + theme(axis.text.x = element_text(angle = 90, vjust=0.5, hjust=0)) +
  theme(legend.title = element_text(size=9), legend.text = element_text(size=7))
taxaplot_ps_top10_phylum <- taxaplot_ps_top10_phylum + guides(fill=guide_legend(title="Top 10 Phyla"))
taxaplot_ps_top10_phylum


ggsave("taxaplot_top10_phylum.tiff", dpi = 300, width = 18, height = 8, units = "in", plot = taxaplot_ps_top10_phylum, path = "./taxaplots/")

Top 10 Genera


#Top 10 GENERA
#Get genus level
ps_genus <- tax_glom(ps_rel, taxrank= "Rank7")
#Get top 10 genera
genus_top10 <- names(sort(taxa_sums(ps_genus), decreasing=TRUE))[1:10]
ps_genus_top10 <- prune_taxa(genus_top10, ps_genus)

# melt the data into a table
ps_genus_melt<- ps_genus_top10 %>%
  psmelt()
#head(ps_genus_melt)

# Plot top 10 phylum by sample
taxaplot_ps_top10_genus = ggplot(ps_genus_melt
                    , aes(x = sample, y=Abundance)) + 
  geom_bar(stat="identity", position="fill", aes(fill = Rank7))  +
  scale_fill_manual(values=c("aquamarine4", "gold3","lightpink", "firebrick","#DA5724","ivory4",
                             "orchid", "#CBD588", "#8569D5", "#D14285")) +
  theme_bw() +
  ylab("Relative Abundance") + xlab("Sample") + theme(axis.text.x = element_text(angle = 90, vjust=0.5, hjust=0)) +
  theme(legend.title = element_text(size=9), legend.text = element_text(size=7))
taxaplot_ps_top10_genus <- taxaplot_ps_top10_genus + guides(fill=guide_legend(title="Top 10 Genera"))
taxaplot_ps_top10_genus


ggsave("taxaplot_top10_genus.tiff", dpi = 300, width = 18, height = 8, units = "in", plot = taxaplot_ps_top10_genus, path = "./taxaplots/")

Top 10 Species


#Top 10 SPECIES
#Get species level
ps_species <- tax_glom(ps_rel, taxrank= "Rank9")
#Get top 10 genera
species_top10 <- names(sort(taxa_sums(ps_species), decreasing=TRUE))[1:10]
ps_species_top10 <- prune_taxa(species_top10, ps_species)

# melt the data into a table
ps_species_melt<- ps_species_top10 %>%
  psmelt()
#head(ps_species_melt)

# Plot top 10 phylum by sample
taxaplot_ps_top10_species = ggplot(ps_species_melt
                    , aes(x = sample, y=Abundance)) + 
  geom_bar(stat="identity", position="fill", aes(fill = Rank9))  +
  scale_fill_manual(values=c("aquamarine4", "gold3","lightpink", "firebrick","#DA5724","ivory4",
                             "orchid", "#CBD588", "#8569D5", "#D14285")) +
  theme_bw() +
  ylab("Relative Abundance") + xlab("Sample") + theme(axis.text.x = element_text(angle = 90, vjust=0.5, hjust=0)) +
  theme(legend.title = element_text(size=9), legend.text = element_text(size=7))
taxaplot_ps_top10_species <- taxaplot_ps_top10_species + guides(fill=guide_legend(title="Top 10 Species"))
taxaplot_ps_top10_species


ggsave("taxaplot_top10_species.tiff", dpi = 300, width = 18, height = 8, units = "in", plot = taxaplot_ps_top10_species, path = "./taxaplots/")
LS0tCnRpdGxlOiAiMTZTIE9OVCBTZXF1ZW5jZSBhbmQgU3RhdGlzdGljYWwgQW5hbHlzaXMiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICBkZl9wcmludDogcGFnZWQKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBGQUxTRSkKYGBgCiMjIE9OVCAxNlMgU2VxdWVuY2luZyBGaWxlcwpSYXcgZmFzdDUgZmlsZXMgZnJvbSBlYWNoIE94Zm9yZCBOYW5vcG9yZSAoT05UKSBzZXF1ZW5jaW5nIGJhdGNoIGNhbiBiZSBmb3VuZCB3aXRoaW4gdGhlIGRpcmVjdG9yeSBuYW1lZDogcmF3X2Zhc3Q1X2ZpbGVzLwoKfCBBIHRvdGFsIG9mIDggc2VxdWVuY2luZyBiYXRjaGVzIHdlcmUgcnVuLiBFYWNoIGJhdGNoIGluY2x1ZGVzIDI0IHNhbXBsZXMgZnJvbSB0aGUgZm9sbG93aW5nIHRyZWF0bWVudCBhbmQgZG9ub3IgaWRzOgoKfCAgICAgICAxLiBVVDEsIFVUMiwgVVQzCgp8ICAgICAgIDIuIFVUNCwgVVQ1LCBVVDYKCnwgICAgICAgMy4gUExBMSwgUExBMiwgUExBMwoKfCAgICAgICA0LiBQTEE0LCBQTEE1LCBQTEE2ICpOT1RFOiBUaGVzZSBzYW1wbGVzIGhhZCB0byBiZSByZS1ydW4gc28gdGhleSByZXByZXNlbnQgdHdvIHNlcGFyYXRlIHNlcXVlbmNpbmcgcnVucwoKfCAgICAgICA1LiBUMS0xLCBUMS0yLCBUMS0zCgp8ICAgICAgIDYuIFQxLTQsIFQxLTUsIFQxLTYKCnwgICAgICAgNy4gVDItMSwgVDItMiwgVDItMwoKfCAgICAgICA4LiBUMi00LCBUMi01LCBUMi02Cgp8IFNvIGZvciBleGFtcGxlLCB0aGUgcmF3IGZhc3Q1IGZpbGVzIG9mIHNhbXBsZXMgd2l0aGluIFVUMSwgVVQyLCBVVDMgd291bGQgYmUgaW46IHJhd19mYXN0NV9maWxlcy9VVDFfVVQyX1VUM19mYXN0NXMvCgojIyBPTlQgMTZTIFNlcXVlbmNlIFFDIFBpcGVsaW5lCgp8IEFmdGVyIE9OVCBzZXF1ZW5jaW5nIHRoZSBmb2xsb3dpbmcgcGlwZWxpbmUgd2FzIHVzZWQgdG8gZGVtdWx0aXBsZXggYW5kIHF1YWxpdHkgZmlsdGVyIHJlYWRzOgoKfCAxLiBCYXNlY2FsbCB3aXRoIERvcmFkbyBWIDAuNC4xIGh0dHBzOi8vZ2l0aHViLmNvbS9uYW5vcG9yZXRlY2gvZG9yYWRvCgp8IDIuIERlbXVsdGlwbGV4IHdpdGggR3VwcHkgViA2LjQuNiAoZ3VwcHlfYmFyY29kZXI6IGh0dHBzOi8vY29tbXVuaXR5Lm5hbm9wb3JldGVjaC5jb20vZG9jcy9wcmVwYXJlL2xpYnJhcnlfcHJlcF9wcm90b2NvbHMvR3VwcHktcHJvdG9jb2wvdi9ncGJfMjAwM192MV9yZXZheF8xNGRlYzIwMTgvYmFyY29kaW5nLWRlbXVsdGlwbGV4aW5nKSAKCnwgMy4gUmVhZCBxdWFsaXR5IGZpbHRlcmluZyBhbmQgdHJpbW1pbmcgd2l0aCBDaG9wcGVyIFYgMC42LjAgaHR0cHM6Ly9naXRodWIuY29tL3dkZWNvc3Rlci9jaG9wcGVyIAp8ICAgIFRyaW1tZWQgZmFzdHEgZmlsZXMgY2FuIGJlIGZvdW5kIGluIHRoZSBkaXJlY3RvcnkgbmFtZWQ6IHRyaW1tZWRfZmFzdHFzCgp8ICAgICAgIENob3BwZXIgcGFyYW1ldGVycyB1c2VkOgoKfCAgICAgICAgICAg4oCiCU1pbiBxIHNjb3JlOiAxMAoKfCAgICAgICAgICAg4oCiCU1pbiBsZW5ndGg6IDEsMDAwIGJwIAoKfCAgICAgICAgICAg4oCiCUhlYWQgY3JvcDogNTAKCnwgICAgICAgICAgIOKAoglNYXggbGVuZ3RoOiAxNjkwCgp8IDQuIE11bHRpcWMgcmVzdWx0cyBzdW1tYXJ5IHVzaW5nIGZhc3RwIHFjIFYgMC4yMC4xIAp8ICAgIE11bHRpcWMgcmVzdWx0cyBmb3IgZWFjaCBzZXF1ZW5jaW5nIGJhdGNoIGNhbiBiZSBmb3VuZCBpbiB0aGUgZGlyZWN0b3J5IG5hbWVkOiBtdWx0aXFjCgp8IEZ1bGwgcGlwZWxpbmUgd2l0aCBjb2RlIGlzIGF2YWlsYWJsZSBhdDogaHR0cHM6Ly9naXRodWIuY29tL01lc3N5YXN6QS9PTlRfZGVtdXggCgojIyMgVGF4b25vbWljIENsYXNzaWZpY2F0aW9uClF1YWxpdHkgZmlsdGVyZWQgYW5kIHRyaW1tZWQgcmVhZHMgd2VyZSB0aGVuIGFsaWduZWQgdG8gdGhlIEhPTUQgZGF0YWJhc2UgYW5kIGJpb20gZmlsZXMgd2VyZSBjcmVhdGVkIGZvciBpbXBvcnQgaW50byBwaHlsb3NlcS4KCm8JRmlyc3QsIGJ1aWx0IGEgS3Jha2VuMiBkYXRhYmFzZSBvZiB0aGUgMTZTIEhPTUQgc2VxdWVuY2VzIChodHRwczovL3d3dy5ob21kLm9yZy9mdHAvMTZTX3JSTkFfcmVmc2VxL0hPTURfMTZTX3JSTkFfUmVmU2VxL2N1cnJlbnQvSE9NRF8xNlNfclJOQV9SZWZTZXFfVjE1LjIzLmZhc3RhKSAKCnwgMS4gVGF4b25vbWljYWxseSBjbGFzc2lmaWVkIHJlYWRzIHZpYSBLcmFrZW4yIHRvIHRoZSBidWlsdCBIT01EIDE2UyBkYXRhYmFzZQoKfCAyLiBFc3RpbWF0ZWQgYWJ1bmRhbmNlIG9mIHRheGEgdmlhIEJyYWNrZW4gaHR0cHM6Ly9jY2Iuamh1LmVkdS9zb2Z0d2FyZS9icmFja2VuLyAKfCAgICAgICBLcm9uYSBncmFwaHMgb2YgdGhlIEJyYWNrZW4gYWJ1bmRhbmNlIGVzdGltYXRlcyBmb3IgZWFjaCBzYW1wbGUgY2FuIGJlIGZvdW5kIGluIHRoZSBkaXJlY3RvcnkgbmFtZWQ6IGtyb25hX2JyYWNrZW4KCnwgMy4gRXhwb3J0ZWQgQnJhY2tlbiByZXN1bHRzIGFzIGEgYmlvbSBmaWxlIGZvciBpbXBvcnQgaW50byBwaGx5b3NlcSAodmlhIHRheHBhc3RhIFYgMC42LjEgaHR0cHM6Ly90YXhwYXN0YS5yZWFkdGhlZG9jcy5pby9lbi9sYXRlc3QvKSAKCnwgRnVsbCBwaXBlbGluZSB3aXRoIGNvZGUgZm9yIHRoZXNlIDMgc3RlcHMgaXMgYXZhaWxhYmxlIGF0OiBodHRwczovL2dpdGh1Yi5jb20vTWVzc3lhc3pBL2JyYWNrZW5fdGF4cGFzdGEgCgojIyBTdGF0aXN0aWNhbCBBbmFseXNpcwpEaXZlcnNpdHksIGRpZmZlcmVudGlhbCBhYnVuZGFuY2UsIGFuZCByZWxhdGl2ZSBhYnVuZGFuY2Ugb2YgdGF4YSB3ZXJlIGFuYWx5emVkIHZpYSBQaHlsb3NlcSBhbmQgc3RhdGlzdGljYWwgdGVzdHMgd2VyZSBydW4gYmV0d2VlbiB0aGUgNCB0cmVhdG1lbnRzLiAKClRoZSBiaW9tIGZpbGUgYW5kIG1ldGFkYXRhIHRhYmxlIGltcG9ydGVkIGludG8gcGh5bG9zZXEgY2FuIGJlIGZvdW5kIGluIHRoZSBkaXJlY3RvcnkgbmFtZWQ6IHN0YXRzX2FuYWx5c2lzCgpSZXN1bHRzIGluY2x1ZGU6Cgp8IG8gQWxwaGEgZGl2ZXJzaXR5IG1ldHJpY3MgLSBPYnNlcnZlZCwgU2hhbm5vbiwgU2ltcHNvbiAoY3N2IHRhYmxlcyBpbiBzdGF0c19hbmFseXNpcyBkaXJlY3RvcnkpCgp8IG8JQWxwaGEgZGl2ZXJzaXR5IHN0YXRpc3RpY2FsIHRlc3RzIChyZXN1bHRzIGJlbG93KQoKfCBvCUFscGhhIGRpdmVyc2l0eSBib3hwbG90cyAodGlmZiBpbWFnZXMgaW4gc3RhdHNfYW5hbHlzaXMvYWxwaGFfZGl2ZXJzaXR5X3Bsb3RzIGRpcmVjdG9yeSkKCnwgICAgICAg4oCiCSpOT1RFOiBPYnNlcnZlZCByaWNobmVzcyB3YXMgcnVuIG9uIHJhdyBhbmQgbm9ybWFsaXplZCBkYXRhLiBSYXJlZmFjdGlvbiB0byBsb3dlc3QgcmVhZCBudW1iZXIgd2FzIHVzZWQgYXMgbm9ybWFsaXphdGlvbi4KfCAgICAgICBUaGlzIHdhcyBpbmNsdWRlZCBmb3IgY29tcGFyYXRpdmUgcHVycG9zZXMuIE90aGVyIG5vcm1hbGl6YXRpb24gbWV0aG9kcyBjYW4gYWxzbyBiZSBydW4gaWYgcmVxdWVzdGVkLgoKfCBvCVBhaXJ3aXNlIGRpZmZlcmVudGlhbCBhYnVuZGFuY2UgdGVzdCB2aWEgRGVTZXEyIChjc3YgdGFibGUgcmVzdWx0cyBpbiBzdGF0c19hbmFseXNpcy9ERVNFUTIgZGlyZWN0b3J5KQoKfCAgICAgICDigKIJVm9sY2FubyBwbG90ICh0aWZmIGltYWdlIGluIHN0YXRzX2FuYWx5c2lzL0RFU0VRMiBkaXJlY3RvcnkpCgp8ICAgICAgIOKAogkqTk9URTogQW5vdGhlciBkaWZmZXJlbnRpYWwgYWJ1bmRhbmNlIG1ldGhvZCBmb3IgbWljcm9iaW9tZSBkYXRhIChBTkNPTS1CQwp8ICAgICAgIGh0dHBzOi8vd3d3LmJpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL2h0bWwvQU5DT01CQy5odG1sICkgY2FuIGJlIHJ1biBpZiByZXF1ZXN0ZWQuCgoKfCBvCUJldGEgZGl2ZXJzaXR5IHN0YXRpc3RpY2FsIHRlc3RzIC0gQnJheS1DdXJ0aXMsIEV1Y2xpZGVhbiBkaXN0YW5jZXMKCnwgICAgICAg4oCiCSpOT1RFOiBNZXRob2RzIGZvciBub3JtYWxpemluZyBiZXRhIGRpdmVyc2l0eSBtZXRyaWNzIChpLmUuIGNhbGN1bGF0aW5nIEFpdGNoaXNvbiBkaXN0YW5jZSB2aWEgdGhlIGRlaWNvZGUgcGFja2FnZSBpbiBRaWltZTIKfCAgICAgICBodHRwczovL2xpYnJhcnkucWlpbWUyLm9yZy9wbHVnaW5zL2RlaWNvZGUvMTkvKSBjYW4gYmUgcnVuIGlmIHJlcXVlc3RlZC4gCgp8IG8JQmV0YSBkaXZlcnNpdHkgcGxvdHMgKHRpZmYgaW1hZ2VzIGluIHN0YXRzX2FuYWx5c2lzL2JldGFfZGl2ZXJzaXR5X3Bsb3RzIGRpcmVjdG9yeSkKCnwgbwlSZWxhdGl2ZSBhYnVuZGFuY2UgdGF4YSBwbG90cyAodGlmZiBpbWFnZXMgY2FuIGJlIGZvdW5kIGluIHN0YXRzX2FuYWx5c2lzL3RheGFwbG90cyBkaXJlY3RvcnkpCmBgYHtyIExpYnJhcmllcywgIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojTGlicmFyaWVzIHdlIHdpbGwgdXNlCmxpYnJhcnkoIkRFU2VxMiIpCmxpYnJhcnkoImdncGxvdDIiKQpsaWJyYXJ5KEJpb3N0cmluZ3MpCmxpYnJhcnkoInBoeWxvc2VxIikKbGlicmFyeSgibWljcm9iaW9tZSIpCmxpYnJhcnkoImdndGhlbWVzIikKbGlicmFyeShnZ25ldHdvcmspCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeSgidmVnYW4iKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KEVuaGFuY2VkVm9sY2FubykKCiNDcmVhdGUgYSBmZXcgb3V0cHV0IGRpcmVjdG9yaWVzIHRoYXQgd2lsbCBob2xkIHRoZSBvdXRwdXQgZmlsZXMuIApkaXIuY3JlYXRlKCcuL0RFU0VRMicpCmRpci5jcmVhdGUoJy4vQU5DT00nKQpgYGAKCmBgYHtyIGRhdGFfbG9hZDEsIHdhcm5pbmc9RkFMU0V9CiMgTG9hZCBkYXRhIGFuZCBhZGQgbWV0YWRhdGEKcHNfb2JqZWN0IDwtIGltcG9ydF9iaW9tKCIuL0hPTURfYmlvbV9tZXJnZS5iaW9tIikKCiNpbXBvcnQgbWVkYXRhIGFuZCBhZGQgdG8gcGh5bG9zZXEgb2JqZWN0Cm1ldGFkYXRhIDwtIHJlYWQuY3N2KCIuL21ldGFkYXRhLmNzdiIsIHJvdy5uYW1lcyA9IDEpCm1ldGFkYXRhID0gc2FtcGxlX2RhdGEoZGF0YS5mcmFtZShtZXRhZGF0YSkpCnNhbXBsZV9kYXRhKHBzX29iamVjdCkgPC0gbWV0YWRhdGEKYGBgCiMjIFN0YXRpc3RpY2FsIEFuYWx5c2lzIFJlc3VsdHMKCiMjIyBUb3RhbCBudW1iZXIgb2YgdGF4YQpUaGUgdG90YWwgbnVtYmVyIG9mIHRheG9ub21pY2FsbHkgaWRlbnRpZmllZCBBU1ZzIGFjcm9zcyBhbGwgc2FtcGxlcwpgYGB7ciBkYXRhX2xvYWQyLCB3YXJuaW5nPUZBTFNFfQojQ2hlY2sgc2FtcGxlIG51bWJlcnMKbnRheGEocHNfb2JqZWN0KSAjVG90YWwgdGF4YQpgYGAKIyMjIE51bWJlciBvZiB0YXhvbm9taWNhbGx5IGNsYXNzaWZpZWQgcmVhZHMgcGVyIHNhbXBsZQpTYW1wbGVzIHdpbGwgaGF2ZSB2YXJ5aW5nIG51bWJlcnMgb2YgdGF4b25vbWljYWxseSBjbGFzc2lmaWVkIHJlYWRzIGR1ZSB0byBkaWZmZXJlbnQgc2FtcGxpbmcgZGVwdGhzIGR1cmluZyBzZXF1ZW5jaW5nLiAKYGBge3IgZGF0YV9sb2FkMywgd2FybmluZz1GQUxTRX0KI0NoZWNrIHNhbXBsZSBudW1iZXJzCnNhbXBsZV9zdW1zKHBzX29iamVjdCkgI1JlYWRzIHBlciBzYW1wbGUKYGBgCiMjIEFscGhhIERpdmVyc2l0eQpNZWFzdXJpbmcgc3BlY2llcyBkaXZlcnNpdHkgd2l0aGluIGVhY2ggc2FtcGxlLgpgYGB7ciBmdW5jdGlvbnN9CiNGdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIG1lYW4gYW5kIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gZm9yIGVhY2ggZ3JvdXAuCiNkYXRhIDogYSBkYXRhIGZyYW1lCiN2YXJuYW1lIDogdGhlIG5hbWUgb2YgYSBjb2x1bW4gY29udGFpbmluZyB0aGUgdmFyaWFibGUgdG8gYmUgc3VtbWFyaXplZAojZ3JvdXBuYW1lcyA6IHZlY3RvciBvZiBjb2x1bW4gbmFtZXMgdG8gYmUgdXNlZCBhcyBncm91cGluZyB2YXJpYWJsZXMKCiMgQ2FsY3VsYXRlIHN0YW5kYXJkIGVycm9yCnNkZXJyIDwtIGZ1bmN0aW9uKHgpIHtzZCh4KS9zcXJ0KGxlbmd0aCh4KSl9CgpkYXRhX3N1bW1hcnkgPC0gZnVuY3Rpb24oZGF0YSwgdmFybmFtZSwgZ3JvdXBuYW1lcyl7CiAgcmVxdWlyZShwbHlyKQogIHN1bW1hcnlfZnVuYyA8LSBmdW5jdGlvbih4LCBjb2wpewogICAgYyhtZWFuID0gbWVhbih4W1tjb2xdXSwgbmEucm09VFJVRSksCiAgICAgIHNkID0gc2RlcnIoeFtbY29sXV0pLCBuYS5ybT1UUlVFKQogIH0KICBkYXRhX3N1bTwtZGRwbHkoZGF0YSwgZ3JvdXBuYW1lcywgLmZ1bj1zdW1tYXJ5X2Z1bmMsCiAgICAgICAgICAgICAgICAgIHZhcm5hbWUpCiAgZGF0YV9zdW0gPC0gcmVuYW1lKGRhdGFfc3VtLCBjKCJtZWFuIiA9IHZhcm5hbWUpKQogIHJldHVybihkYXRhX3N1bSkKfQpgYGAKCiMjIyBEYXRhIHRhYmxlIHdpdGggYWxwaGEgZGl2ZXJzaXR5IG1ldHJpY3M6IE9ic2VydmVkLCBTaGFubm9uLCBTaW1wc29uCiMjIyMgRXhhbXBsZSBvZiBkYXRhIHRhYmxlIHN0cnVjdHVyZSAoZnVsbCB0YWJsZSBzYXZlZCBhcyBjc3YpClRocmVlIGFscGhhIGRpdmVyc2l0eSBtZXRyaWNzIGFyZSBjYWxjdWxhdGVkIGZvciBlYWNoIHNhbXBsZS4KVGhlIGZ1bGwgdGFibGUgKHBlcl9zYW1wbGVfYWRfZGF0YWZyYW1lLmNzdikgY2FuIGJlIGZvdW5kIGluIHRoZSBkaXJlY3RvcnkgbmFtZWQ6IHN0YXRzX2FuYWx5c2lzCmBgYHtyIGRhdGFfdGFibGUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRX0KYWxwaGFfZGl2IDwtIGNiaW5kKGVzdGltYXRlX3JpY2huZXNzKHBzX29iamVjdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYXN1cmVzID0gYygnT2JzZXJ2ZWQnLCAnU2hhbm5vbicsICdTaW1wc29uJykpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVfZGF0YShwc19vYmplY3QpKQpjb2xuYW1lcyhhbHBoYV9kaXYpIDwtIGMoJ09ic2VydmVkJywgJ1NoYW5ub24nLCAnU2ltcHNvbicpCmFscGhhX2RpdiRMYWJlbHMgPC0gcm93bmFtZXMoYWxwaGFfZGl2KQphZF9kZiA8LSBhbHBoYV9kaXZbLGMoJ09ic2VydmVkJywgJ1NoYW5ub24nLCAnU2ltcHNvbicpXQphZF9kZiA8LSBjYmluZChhZF9kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlX2RhdGEocHNfb2JqZWN0KVssIGMoJ3NhbXBsZScsICdncm91cCcsICdkb25vcicsICd0cmVhdG1lbnQnKV0pCmNvbG5hbWVzKGFkX2RmKSA8LSBjKCdPYnNlcnZlZCcsICdTaGFubm9uJywgJ1NpbXBzb24nLCAnc2FtcGxlJywgJ2dyb3VwJywgJ2Rvbm9yJywgJ3RyZWF0bWVudCcpCmhlYWQoYWRfZGYpCndyaXRlLmNzdihhZF9kZiwgIi4vcGVyX3NhbXBsZV9hZF9kYXRhZnJhbWUuY3N2IikKYGBgCiMjIyBEYXRhIFN1bW1hcnkgc3RhdGlzdGljczogT2JzZXJ2ZWQsIFNoYW5ub24sIFNpbXBzb24KIyMjIyBTdW1tYXJ5IGZvciBlYWNoIHRyZWF0bWVudApUaGUgYXZlcmFnZSBvZiBlYWNoIGFscGhhIGRpdmVyc2l0eSBtZXRyaWMgZm9yIGFsbCBzYW1wbGVzIHdpdGhpbiBhIHRyZWF0bWVudC4gCmBgYHtyIHN1bW1hcnlfc3RhdHMsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRX0KIyBPYnNlcnZlZApkYXRhX3N1bW1hcnkoYWRfZGYsIHZhcm5hbWUgPSAiT2JzZXJ2ZWQiLCBncm91cG5hbWVzID0gYygidHJlYXRtZW50IikpCiNkYXRhX3N1bW1hcnkoYWRfZGYsIHZhcm5hbWUgPSAiT2JzZXJ2ZWQiLCBncm91cG5hbWVzID0gYygic2FtcGxlIikpCiNkYXRhX3N1bW1hcnkoYWRfZGYsIHZhcm5hbWUgPSAiT2JzZXJ2ZWQiLCBncm91cG5hbWVzID0gYygiZG9ub3IiKSkKCiMgU2hhbm5vbgpkYXRhX3N1bW1hcnkoYWRfZGYsIHZhcm5hbWUgPSAiU2hhbm5vbiIsIGdyb3VwbmFtZXMgPSBjKCJ0cmVhdG1lbnQiKSkKI2RhdGFfc3VtbWFyeShhZF9kZiwgdmFybmFtZSA9ICJTaGFubm9uIiwgZ3JvdXBuYW1lcyA9IGMoInNhbXBsZSIpKQojZGF0YV9zdW1tYXJ5KGFkX2RmLCB2YXJuYW1lID0gIlNoYW5ub24iLCBncm91cG5hbWVzID0gYygiZG9ub3IiKSkKCiMgU2ltcHNvbgpkYXRhX3N1bW1hcnkoYWRfZGYsIHZhcm5hbWUgPSAiU2ltcHNvbiIsIGdyb3VwbmFtZXMgPSBjKCJ0cmVhdG1lbnQiKSkKI2RhdGFfc3VtbWFyeShhZF9kZiwgdmFybmFtZSA9ICJTaW1wc29uIiwgZ3JvdXBuYW1lcyA9IGMoInNhbXBsZSIpKQojZGF0YV9zdW1tYXJ5KGFkX2RmLCB2YXJuYW1lID0gIlNpbXBzb24iLCBncm91cG5hbWVzID0gYygiZG9ub3IiKSkKYGBgCiMjIyBBbHBoYSBkaXZlcnNpdHkgc3RhdGlzdGljYWwgdGVzdHMgZm9yIHNpZ25pZmljYW5jZQojIyMjIEtydXNrYWwgV2FsbGlzIGFuZCBQYWlyd2lzZSBXaWxjb3hvbiB0ZXN0cwpLcnVza2FsLVdhbGxpcyBSYW5rIFN1bSBUZXN0IGZvciBhIGNhdGVnb3J5ICh0cmVhdG1lbnQpIG9uIGVhY2ggQWxwaGEgRGl2ZXJzaXR5IG1ldHJpYyBjYWxjdWxhdGVkLiBUaGlzIGlzIGEgbm9uLXBhcmFtZXRyaWMgbWV0aG9kIHdoaWNoIHJhbmtzIHRoZSBkYXRhIGFuZCB0ZXN0cyB3aGV0aGVyIHNhbXBsZXMgZnJvbSBlYWNoIGdyb3VwIGFuYWx5emVkIGNvbWUgZnJvbSB0aGUgc2FtZSBkaXN0cmlidXRpb24uIAoKUGFpcndpc2UgV2lsY294b24gUmFuayBTdW0gVGVzdCBiZXR3ZWVuIGdyb3VwcyB3aXRoaW4gYSBjYXRlZ29yeSAodHJlYXRtZW50KSBvbiBlYWNoIEFscGhhIERpdmVyc2l0eSBtZXRyaWMgY2FsY3VsYXRlZCBhbmQgY29ycmVjdGVkIGZvciBtdWx0aXBsZSB0ZXN0aW5nLiBUaGlzIG1ldGhvZHMgY29tcGFyZXMgdHdvIGluZGVwZW5kZW50IHNhbXBsZXMgZm9yIGFsbCBncm91cCBsZXZlbHMgYW5kIGluY2x1ZGVzIHRoZSBmYWxzZSBkaXNjb3ZlcnkgcmF0ZSAoRkRSKSBtdWx0aXBsZSB0ZXN0IGNvcnJlY3Rpb24uIFRoZSByZXN1bHRzIGJlbG93IGNvbWUgdXAgYXMgYSBtYXRyaXggZmlsbGVkIHdpdGggdGhlIHAtdmFsdWVzIGZvciBlYWNoIHRyZWF0bWVudCBjb21wYXJpc29uLgoKIyMjIyBPYnNlcnZlZCBSaWNobmVzcyAKVGVzdGluZyBBU1Yvc3BlY2llcyByaWNobmVzcyBiZXR3ZWVuIHRoZSA0IHRyZWF0bWVudHMuCmBgYHtyIG9ic2VydmVkX2FkLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMjIyMgT2JzZXJ2ZWQKI0tydXNrYWwgV2FsbGlzIHRlc3RzCmtydXNrYWwudGVzdChPYnNlcnZlZCB+IHRyZWF0bWVudCwgZGF0YSA9IGFkX2RmKQoja3J1c2thbC50ZXN0KE9ic2VydmVkIH4gc2FtcGxlLCBkYXRhID0gYWRfZGYpCiNrcnVza2FsLnRlc3QoT2JzZXJ2ZWQgfiBkb25vciwgZGF0YSA9IGFkX2RmKQoKI1BhaXJ3aXNlIFdpbGNveG9uIFRlc3QKcGFpcndpc2Uud2lsY294LnRlc3QoYWRfZGYkT2JzZXJ2ZWQsIGFkX2RmJHRyZWF0bWVudCwgcC5hZGp1c3QubWV0aG9kID0gJ2ZkcicpCmBgYAojIyMjIFNoYW5ub24gRGl2ZXJzaXR5ClRlc3RpbmcgQVNWL3NwZWNpZXMgcmljaG5lc3MgYmV0d2VlbiB0aGUgNCB0cmVhdG1lbnRzIHdoaWxlIGFsc28gdGFraW5nIGludG8gYWNjb3VudCByZWxhdGl2ZSBhYnVuZGFuY2UgKGV2ZW5uZXNzKS4KYGBge3Igc2hhbm5vbl9hZCwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFfQojIyMjIFNoYW5ub24KI0tydXNrYWwgV2FsbGlzIHRlc3RzCmtydXNrYWwudGVzdChTaGFubm9uIH4gdHJlYXRtZW50LCBkYXRhID0gYWRfZGYpCiNrcnVza2FsLnRlc3QoU2hhbm5vbiB+IHNhbXBsZSwgZGF0YSA9IGFkX2RmKQoja3J1c2thbC50ZXN0KFNoYW5ub24gfiBkb25vciwgZGF0YSA9IGFkX2RmKQoKI1BhaXJ3aXNlIFdpbGNveG9uIFRlc3QKcGFpcndpc2Uud2lsY294LnRlc3QoYWRfZGYkU2hhbm5vbiwgYWRfZGYkdHJlYXRtZW50LCBwLmFkanVzdC5tZXRob2QgPSAnZmRyJykKYGBgCiMjIyMgU2ltcHNvbiBEaXZlcnNpdHkKVGVzdGluZyBBU1Yvc3BlY2llcyByaWNobmVzcyBiZXR3ZWVuIHRoZSA0IHRyZWF0bWVudHMgd2hpbGUgYWxzbyB0YWtpbmcgaW50byBhY2NvdW50IHJlbGF0aXZlIGFidW5kYW5jZSAoZXZlbm5lc3MpLiBTaW1wc29uIGRpdmVyc2l0eSBnaXZlcyBtb3JlIHdlaWdodCB0byBjb21tb24gb3IgZG9taW5hbnQgQVNWcyAocmFyZSBBU1ZzIHdpbGwgbm90IGFmZmVjdCBkaXZlcnNpdHkpLgpgYGB7ciBzaW1wc29uX2FkLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMjIyMgU2ltcHNvbgojS3J1c2thbCBXYWxsaXMgdGVzdHMKa3J1c2thbC50ZXN0KFNpbXBzb24gfiB0cmVhdG1lbnQsIGRhdGEgPSBhZF9kZikKI2tydXNrYWwudGVzdChTaW1wc29uIH4gc2FtcGxlLCBkYXRhID0gYWRfZGYpCiNrcnVza2FsLnRlc3QoU2ltcHNvbiB+IGRvbm9yLCBkYXRhID0gYWRfZGYpCgojUGFpcndpc2UgV2lsY294b24gVGVzdApwYWlyd2lzZS53aWxjb3gudGVzdChhZF9kZiRTaW1wc29uLCBhZF9kZiR0cmVhdG1lbnQsIHAuYWRqdXN0Lm1ldGhvZCA9ICdmZHInKQpgYGAKCiMjIyBBbHBoYSBkaXZlcnNpdHkgYm94cGxvdHMKSW1hZ2VzIG9mIGVhY2ggcGxvdCBjYW4gYmUgZm91bmQgaW46IHN0YXRzX2FuYWx5c2lzL2FscGhhX2RpdmVyc2l0eV9wbG90cwpgYGB7ciBBRCwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLmFsaWduPSJjZW50ZXIiLCByZXN1bHRzPSdoaWRlJywgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9N30KIyMjR3JvdXAgcGxvdHMKI09ic2VydmVkCm9ic19hZF9wbG90IDwtIGdncGxvdChhZF9kZiwgYWVzKHg9dHJlYXRtZW50LCB5PU9ic2VydmVkLCBjb2xvciA9IHRyZWF0bWVudCkpICsgZ2VvbV9ib3hwbG90KCkgKyBnZW9tX3BvaW50KCkgKyB5bGFiKCdPYnNlcnZlZCBSaWNobmVzcycpICsgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjOTU0NTM1IiwgIiM3MDI5NjMiLCAiI0YyOEMyOCIsICIjMDg4RjhGIikpCgpvYnNfYWRfcGxvdAoKZ2dzYXZlKCJvYnNfYWRfcGxvdC50aWZmIiwgZHBpID0gMzAwLCBwbG90ID0gb2JzX2FkX3Bsb3QsIHBhdGggPSAiLi9hbHBoYV9kaXZlcnNpdHlfcGxvdHMvIikKCiNTaGFubm9uCnNoYW5fYWRfcGxvdCA8LSBnZ3Bsb3QoYWRfZGYsIGFlcyh4PXRyZWF0bWVudCwgeT1TaGFubm9uLCBjb2xvciA9IHRyZWF0bWVudCkpICsgZ2VvbV9ib3hwbG90KCkgKyBnZW9tX3BvaW50KCkgKyB5bGFiKCdTaGFubm9uIERpdmVyc2l0eScpICsgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjOTU0NTM1IiwgIiM3MDI5NjMiLCAiI0YyOEMyOCIsICIjMDg4RjhGIikpCgpzaGFuX2FkX3Bsb3QKCmdnc2F2ZSgic2hhbl9hZF9wbG90LnRpZmYiLCBkcGkgPSAzMDAsIHBsb3QgPSBzaGFuX2FkX3Bsb3QsIHBhdGggPSAiLi9hbHBoYV9kaXZlcnNpdHlfcGxvdHMvIikKCiNTaW1wc29uCnNpbXBfYWRfcGxvdCA8LSBnZ3Bsb3QoYWRfZGYsIGFlcyh4PXRyZWF0bWVudCwgeT1TaW1wc29uLCBjb2xvciA9IHRyZWF0bWVudCkpICsgZ2VvbV9ib3hwbG90KCkgKyBnZW9tX3BvaW50KCkgKyB5bGFiKCdTaW1wc29uIERpdmVyc2l0eScpICsgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjOTU0NTM1IiwgIiM3MDI5NjMiLCAiI0YyOEMyOCIsICIjMDg4RjhGIikpCgpzaW1wX2FkX3Bsb3QKCmdnc2F2ZSgic2ltcF9hZF9wbG90LnRpZmYiLCBkcGkgPSAzMDAsIHBsb3QgPSBzaW1wX2FkX3Bsb3QsIHBhdGggPSAiLi9hbHBoYV9kaXZlcnNpdHlfcGxvdHMvIikKYGBgCiMjIEFscGhhIERpdmVyc2l0eSBvbiBSYXJlZmllZCBEYXRhCiMjIyBOb3JtYWxpemUgT2JzZXJ2ZWQgUmljaG5lc3MgbWV0cmljIGJ5IHJhcmVmeWluZyB0byBsb3dlc3Qgc2FtcGxlIHN1bSBudW1iZXIKU2hhbm5vbiBhbmQgU2ltcHNvbiBkaXZlcnNpdHkgaW5kaWNlcyBhcmUgYWxyZWFkeSBub3JtYWxpemVkIGJ5IHJlbGF0aXZlIGFidW5kYW5jZS4gCgojIyMgUmFyZWZhY3Rpb24gcmVhZCBkZXB0aApPbmUgbWV0aG9kIG9mIG5vcm1hbGl6YXRpb24gaXMgdG8gcmFyZWZ5IGVhY2ggc2FtcGxlIHRvIHRoZSBtaW5pbXVtIHJlYWQgZGVwdGggZm91bmQgYWNyb3NzIGFsbCBzYW1wbGVzLiBUaGUgbWluaW11bSByZWFkIGRlcHRoIGZvciBhbGwgc2FtcGxlcyBpczogCmBgYHtyIHJhcmVfbnVtLCB3YXJuaW5nPUZBTFNFfQptaW4oc2FtcGxlX3N1bXMocHNfb2JqZWN0KSkgI01pbmltdW0gcmVhZHMgKHVzZWQgZm9yIHJhcmVmeWluZykKYGBgCiMjIyMgRXhhbXBsZSBvZiBkYXRhdGFibGUgc3RydWN0dXJlIGZvciByYXJlZmllZCBkYXRhIG9ic2VydmVkIHJpY2huZXNzIChmdWxsIHRhYmxlIHNhdmVkIGFzIGNzdikKT2JzZXJ2ZWQgcmljaG5lc3MgaXMgY2FsY3VsYXRlZCBmb3IgZWFjaCBzYW1wbGUgbm93IHJhcmVmaWVkIHRvIHRoZSBtaW5pbXVtIHJlYWQgZGVwdGguClRoZSBmdWxsIHRhYmxlIChyYXJlZmllZF9wZXJfc2FtcGxlX2FkX2RhdGFmcmFtZS5jc3YpIGNhbiBiZSBmb3VuZCBpbiB0aGUgZGlyZWN0b3J5IG5hbWVkOiBzdGF0c19hbmFseXNpcwpgYGB7ciBBRF9yYXJlZmllZCwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KI1JhcmVmeSB0byBsb3dlc3Qgc2FtcGxlX3N1bXMKcmFyZV9udW0gPC0gbWluKHNhbXBsZV9zdW1zKHBzX29iamVjdCkpCnBzX3JhcmUgPC0gcmFyZWZ5X2V2ZW5fZGVwdGgocHNfb2JqZWN0LCBzYW1wbGUuc2l6ZSA9IHJhcmVfbnVtLCBybmdzZWVkID0gOTk5KQoKI0dldCBkYXRhdGFibGUgd2l0aCBPYnNlcnZlZCByaWNobmVzcyBmb3IgcmFyZWZpZWQgc2FtcGxlcwphbHBoYV9kaXZfcmFyZSA8LSBjYmluZChlc3RpbWF0ZV9yaWNobmVzcyhwc19yYXJlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZXMgPSBjKCdPYnNlcnZlZCcpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlX2RhdGEocHNfcmFyZSkpCmNvbG5hbWVzKGFscGhhX2Rpdl9yYXJlKSA8LSBjKCdPYnNlcnZlZF9yYXJlJykKYWxwaGFfZGl2X3JhcmUkTGFiZWxzIDwtIHJvd25hbWVzKGFscGhhX2Rpdl9yYXJlKQphZF9kZl9yYXJlIDwtIGFscGhhX2Rpdl9yYXJlWyxjKCdPYnNlcnZlZF9yYXJlJyldCmFkX2RmX3JhcmUgPC0gY2JpbmQoYWRfZGZfcmFyZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlX2RhdGEocHNfcmFyZSlbLCBjKCdzYW1wbGUnLCAnZ3JvdXAnLCAnZG9ub3InLCAndHJlYXRtZW50JyldKQpjb2xuYW1lcyhhZF9kZl9yYXJlKSA8LSBjKCdPYnNlcnZlZF9yYXJlJywgJ3NhbXBsZScsICdncm91cCcsICdkb25vcicsICd0cmVhdG1lbnQnKQpoZWFkKGFkX2RmX3JhcmUpCndyaXRlLmNzdihhZF9kZl9yYXJlLCAiLi9yYXJlZmllZF9wZXJfc2FtcGxlX2FkX2RhdGFmcmFtZS5jc3YiKQpgYGAKIyMjIyBEYXRhIHN1bW1hcnkgZm9yIHJhcmVmaWVkIGRhdGEgKG9ic2VydmVkIHJpY2huZXNzKQpUaGUgYXZlcmFnZSBvYnNlcnZlZCByaWNobmVzcyBmb3IgYWxsIHNhbXBsZXMgd2l0aGluIGEgdHJlYXRtZW50LiAKYGBge3IgYWRfcmFyZV9zdW1tYXJ5LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQojIE9ic2VydmVkIFJhcmVmaWVkIGRhdGEgc3VtbWFyeSBzdGF0cwpkYXRhX3N1bW1hcnkoYWRfZGZfcmFyZSwgdmFybmFtZSA9ICJPYnNlcnZlZF9yYXJlIiwgZ3JvdXBuYW1lcyA9IGMoInRyZWF0bWVudCIpKQojZGF0YV9zdW1tYXJ5KGFkX2RmX3JhcmUsIHZhcm5hbWUgPSAiT2JzZXJ2ZWRfcmFyZSIsIGdyb3VwbmFtZXMgPSBjKCJzYW1wbGUiKSkKI2RhdGFfc3VtbWFyeShhZF9kZl9yYXJlLCB2YXJuYW1lID0gIk9ic2VydmVkX3JhcmUiLCBncm91cG5hbWVzID0gYygiZG9ub3IiKSkKYGBgCgojIyMjIE9ic2VydmVkIHJpY2huZXNzIHN0YXRpc3RpY2FsIHRlc3RzIGZvciByYXJlZmllZCBkYXRhClRlc3RpbmcgQVNWL3NwZWNpZXMgcmljaG5lc3MgYmV0d2VlbiB0aGUgNCB0cmVhdG1lbnRzLgpgYGB7ciBhZF9yYXJlX3N0YXRzLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQoKIyMjIyBPYnNlcnZlZCBSYXJlZmllZAojS3J1c2thbCBXYWxsaXMgdGVzdHMKa3J1c2thbC50ZXN0KE9ic2VydmVkX3JhcmUgfiB0cmVhdG1lbnQsIGRhdGEgPSBhZF9kZl9yYXJlKQoja3J1c2thbC50ZXN0KE9ic2VydmVkX3JhcmUgfiBzYW1wbGUsIGRhdGEgPSBhZF9kZl9yYXJlKQoja3J1c2thbC50ZXN0KE9ic2VydmVkX3JhcmUgfiBkb25vciwgZGF0YSA9IGFkX2RmX3JhcmUpCgojUGFpcndpc2UgV2lsY294b24gVGVzdApwYWlyd2lzZS53aWxjb3gudGVzdChhZF9kZl9yYXJlJE9ic2VydmVkX3JhcmUsIGFkX2RmX3JhcmUkdHJlYXRtZW50LCBwLmFkanVzdC5tZXRob2QgPSAnZmRyJykKYGBgCiMjIyMgUmFyZWZpZWQgZGF0YSBvYnNlcnZlZCByaWNobmVzcyBib3hwbG90CkltYWdlcyBvZiB0aGUgcGxvdCBjYW4gYmUgZm91bmQgaW46IHN0YXRzX2FuYWx5c2lzL2FscGhhX2RpdmVyc2l0eV9wbG90cwpgYGB7ciBhZF9yYXJlX3Bsb3QsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy5hbGlnbj0iY2VudGVyIiwgcmVzdWx0cz0naGlkZScsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTd9CiNQbG90czogT2JzZXJ2ZWQgUmFyZWZpZWQKb2JzX2FkX3Bsb3RfcmFyZSA8LSBnZ3Bsb3QoYWRfZGZfcmFyZSwgYWVzKHg9dHJlYXRtZW50LCB5PU9ic2VydmVkX3JhcmUsIGNvbG9yID0gdHJlYXRtZW50KSkgKyBnZW9tX2JveHBsb3QoKSArIGdlb21fcG9pbnQoKSArIHlsYWIoJ09ic2VydmVkIFJpY2huZXNzIFJhcmVmaWVkIERhdGEnKSArIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiIzk1NDUzNSIsICIjNzAyOTYzIiwgIiNGMjhDMjgiLCAiIzA4OEY4RiIpKQoKb2JzX2FkX3Bsb3RfcmFyZQoKZ2dzYXZlKCJyYXJlZmllZF9vYnNfYWRfcGxvdC50aWZmIiwgZHBpID0gMzAwLCBwbG90ID0gb2JzX2FkX3Bsb3RfcmFyZSwgcGF0aCA9ICIuL2FscGhhX2RpdmVyc2l0eV9wbG90cy8iKQpgYGAKCiMjIERpZmZlcmVudGlhbCBBYnVuZGFuY2UgQW5hbHlzaXMKIyMjIFBhaXJ3aXNlIGRpZmZlcmVudGlhbCBhYnVuZGFuY2UgdGVzdCBiZXR3ZWVuIHRyZWF0bWVudHMgdmlhIERFU2VxMgpUaGUgcGFja2FnZSBERVNlcTIgcHJvdmlkZXMgbWV0aG9kcyB0byB0ZXN0IGZvciBkaWZmZXJlbnRpYWwgYWJ1bmRhbmNlIGJ5IHVzZSBvZiBuZWdhdGl2ZSBiaW5vbWlhbCBnZW5lcmFsaXplZCBsaW5lYXIgbW9kZWxzLiBERVNlcTIgdXNlcyB0aGUgV2FsZCB0ZXN0IHRvIHRha2UgaW50byBhY2NvdW50IHRoZSBkaXNwZXJzaW9uIG1vZGVsIGRpc3RhbmNlIGFuZCBuZWdhdGl2ZSBiaW5vbWlhbCBkaXN0cmlidXRpb24gd2Ugc2VlIGluIHNlcXVlbmNpbmcgZGF0YS4gT3ZlcmFsbCB0aGlzIG1ldGhvZCBzdGF0aXN0aWNhbGx5IGluZmVycyBzeXN0ZW1hdGljIGNoYW5nZXMgYmV0d2VlbiBjb25kaXRpb25zLCBhcyBjb21wYXJlZCB0byB3aXRoaW4tY29uZGl0aW9uIHZhcmlhYmlsaXR5LiBJdCBlc3RpbWF0ZXMgZGlzcGVyc2lvbiBhbmQgbG9nYXJpdGhtaWMgZm9sZCBjaGFuZ2VzIHRvIHRlc3Qgd2hpY2ggc2VxdWVuY2VzL0FTVnMgYXJlIHNpZ25pZmljYW50bHkgY2hhbmdpbmcgd2l0aGluIHRoZSBleHBlcmltZW50YWwgZGVzaWduLiAKCkFkZGl0aW9uYWxseSwgYSBwLXZhbHVlIGNvcnJlY3Rpb24gaXMgYXBwbGllZCBmb3IgbXVsdGlwbGUgaHlwb3RoZXNpcyB0ZXN0aW5nLiBUcmFkaXRpb25hbGx5IHAgPCAwLjA1IGlzIGNvbnNpZGVyZWQgc2lnbmlmaWNhbnQgKDk1JSBjaGFuY2UgaXQgaXMgbm90IGJ5IHJhbmRvbSBjaGFuY2UpLCBidXQgd2hlbiB5b3UgYXJlIGxvb2tpbmcgYXQgdGhvdXNhbmRzIG9mIEFTVnMvc2VxdWVuY2VzLCB5b3UnbGwgc3RpbGwgZW5kIHVwIHdpdGggNSUgb2YgdGhlbSBzaWduaWZpY2FudCBvZmYgcHJlZGljdGVkIGNoYW5jZS4gT25lIG9mIHRoZSBiZXN0IGNvcnJlY3Rpb25zIHRvIHVzZSBjYWxsZWQgRmFsc2UtRGlzY292ZXJ5IFJhdGUgY29ycmVjdGlvbiAoRkRSKSwgd2hpY2ggaXMgdGhlIEJlbmphbWluaSBhbmQgSG9jaGJlcmcgbWV0aG9kLgoKSGVyZSB3ZSByYW4gREVTZXEyIHNwZWNpZnlpbmcgb25seSB0cmVhdG1lbnQgaW4gdGhlIGV4cGVyaW1lbnRhbCBkZXNpZ24uIExvZyBmb2xkIGNoYW5nZXMgYW5kIGFkanVzdGVkIHAtdmFsdXMgKHBhZGopIGZvciBhbGwgQVNWcyBhbmQgc2lnbmlmaWNhbnQgQVNWcyBoYXZlIGJlZW4gc2F2ZWQgYXMgY3N2IHRhYmxlcyBpbiB0aGUgc3RhdHNfYW5hbHlzaXMvREVTRVEyIGRpcmVjdG9yeSAobmFtZWQgZGRzX3Jlc3VsdF90YWJsZS5jc3YgYW5kIHNpZ19yZXN1bHRfdGFibGUuY3N2IHJlc3BlY3RpdmVseSkuCgpUaGUgYmVsb3cgcGxvdCBzaG93cyB0aGUgZml0dGVkIGN1cnZlIChyZWQgbGluZSkgdXNlZCB0byBjYWxjdWxhdGUgdGhlIGZpbmFsIGRpc3BlcnNpb24gZXN0aW1hdGVzIChibHVlIGRvdHMpIG9mIHRoZSBpbnB1dCBkYXRhIChibGFjayBkb3RzKS4gCmBgYHtyIERlc2VxLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuYWxpZ249ImNlbnRlciIsIHJlc3VsdHM9J2hpZGUnLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD05fQojUGh5bG9zZXEgdG8gRGVzZXEyCnBzX2Rlc2VxID0gcGh5bG9zZXFfdG9fZGVzZXEyKHBzX29iamVjdCwgfnRyZWF0bWVudCkKCiNSdW4gRGVzZXEyCmRkcyA9IERFU2VxKHBzX2Rlc2VxLCB0ZXN0PSJXYWxkIiwgZml0VHlwZT0ibG9jYWwiKQpkZHNfcmVzdWx0IDwtIHJlc3VsdHMoZGRzKQpkZHNfcmVzdWx0X3RhYmxlIDwtIGNiaW5kKGFzKGRkc19yZXN1bHQsICJkYXRhLmZyYW1lIiksIGFzKHRheF90YWJsZShwc19vYmplY3QpW3Jvd25hbWVzKGRkc19yZXN1bHQpLCBdLCAibWF0cml4IikpCndyaXRlLmNzdihkZHNfcmVzdWx0X3RhYmxlLCAiLi9ERVNFUTIvZGRzX3Jlc3VsdF90YWJsZS5jc3YiKQoKI2NoZWNrIHNpZ25pZmljYW50IHJlc3VsdHMKZGRzX3NpZyA9IGRkc19yZXN1bHRbd2hpY2goZGRzX3Jlc3VsdCRwYWRqIDwgMC4wNSksIF0KZGRzX3NpZ190YWJsZSA9IGNiaW5kKGFzKGRkc19zaWcsICJkYXRhLmZyYW1lIiksIGFzKHRheF90YWJsZShwc19vYmplY3QpW3Jvd25hbWVzKGRkc19zaWcpLCBdLCAibWF0cml4IikpCmRpbShkZHNfc2lnX3RhYmxlKQp3cml0ZS5jc3YoZGRzX3NpZ190YWJsZSwgIi4vREVTRVEyL3NpZ19yZXN1bHRfdGFibGUuY3N2IikKCiNQZXJmb3JtIHRoZSB2YXJpYW5jZSBzdGFiaWxpemluZyB0cmFuc2Zvcm1hdGlvbiBvbiB0aGUgZGF0YSBhbmQgcHVsbCB0aGUgbm9ybWFsaXplZCBoaXQgY291bnQgbWF0cml4LiAKdnN0IDwtIHZhcmlhbmNlU3RhYmlsaXppbmdUcmFuc2Zvcm1hdGlvbihkZHMpCm1hdCA8LSBhc3NheSh2c3QpCgojSWYgeW91IGhhdmUgYSBiYXRjaCBkZXNpZ25lZCBpbiwgcmVncmVzcyB0aGUgYmF0Y2ggZWZmZWN0cy4gCiNtYXQgPC0gbGltbWE6OnJlbW92ZUJhdGNoRWZmZWN0KG1hdCwgdnN0JGJhdGNoKQojYXNzYXkodnN0KSA8LSBtYXQKCiNQbG90IHRoZSBvdmVyYWxsIGRpc3BlcnNpb24gb2YgdGhlIGV4cGVyaW1lbnQgdG8gZW5zdXJlIGl0IGFsaWducyB3aXRoIGV4cGVjdGF0aW9ucy4gCnBsb3REaXNwRXN0cyhkZHMpCmBgYAoKIyMjIFZvbGNhbm8gcGxvdDogRGVTZXEyIHJlc3VsdHMKVm9sY2FubyBwbG90cyBhcmUgYSBncmVhdCB3YXkgdG8gdmlzdWFsaXplIHRoZSBwYWlyd2lzZSBjb21wYXJpc29ucy4gRWFjaCBzaG93cyB0aGUgbG9nMiBmb2xkLWNoYW5nZSAobG9nMkZDKSBvbiB0aGUgeC1heGlzIGFuZCAtbG9nMTAocGFkaikgb24gdGhlIHktYXhpcy4gVGhpcyBzaG91bGQgdXN1YWxseSBsb29rIGFraW4gdG8gYSBQbGluaWFuIGVydXB0aW9uIChoZW5jZSB2b2xjYW5vIHBsb3QpLgoKSW1hZ2Ugb2YgdGhlIHZvbGNhbm8gcGxvdCBjYW4gYmUgZm91bmQgaW4gdGhlIHN0YXRzX2FuYWx5c2lzL0RFU0VRMi8gZGlyZWN0b3J5CmBgYHtyIFZvbGNhbm9lcywgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLmFsaWduPSJjZW50ZXIiLCByZXN1bHRzPSdoaWRlJywgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OX0KcCA8LSBFbmhhbmNlZFZvbGNhbm8oZGRzX3Jlc3VsdF90YWJsZSwKICAgICAgICBsYWI9YXMuY2hhcmFjdGVyKGRkc19yZXN1bHRfdGFibGUkUmFuazkpLAogICAgICAgIHRpdGxlPSJQYWlyd2lzZSBjb21wYXJpc29ucyBvZiB0YXhhIChzcGVjaWVzIGxldmVsKSBiZXR3ZWVuIHRyZWF0bWVudHMiLAogICAgICAgIHg9J2xvZzJGb2xkQ2hhbmdlJywKICAgICAgICB5PSdwYWRqJywKICAgICAgICBsZWdlbmRQb3NpdGlvbiA9ICdib3R0b20nLAogICAgICAgIGxlZ2VuZExhYmVscz1jKCdOb3Qgc2lnLicsJ0xvZyAoYmFzZSAyKSBGQycsJ3BhZGotdmFsdWUnLCdwYWRqLXZhbHVlICYgTG9nIChiYXNlIDIpIEZDJyksCiAgICAgICAgcEN1dG9mZj0wLjA1LCAKICAgICAgICBGQ2N1dG9mZj0xCiAgICAgICAgKQpwcmludChwKQpnZ3NhdmUoInZvbGNhbm9fcGxvdC50aWZmIiwgZHBpID0gMzAwLCBwbG90ID0gcCwgcGF0aCA9ICIuL0RFU0VRMi8iKQpgYGAKIyMgQmV0YSBEaXZlcnNpdHkKTWVhc3VyaW5nIHNwZWNpZXMgZGl2ZXJzaXR5IG9yIHRoZSBsZXZlbCBvciBzaW1pbGFyaXR5L2Rpc3NpbWlsYXJpdHkgb2Ygc3BlY2llcyBiZXR3ZWVuIHNhbXBsZXMuCmBgYHtyfQojUGFpcndpc2UgQWRvbmlzIGZ1bmN0aW9uCnBhaXJ3aXNlLmFkb25pcy5kbSA8LSBmdW5jdGlvbih4LGZhY3RvcnMsc3RyYXR1bT1OVUxMLHAuYWRqdXN0Lm09ImZkciIscGVybT05OTkpewogIAogIGxpYnJhcnkodmVnYW4pCiAgaWYoY2xhc3MoeCkgIT0gImRpc3QiKSBzdG9wKCJ4IG11c3QgYmUgYSBkaXNzaW1pbGFyaXR5IG1hdHJpeCAoZGlzdCBvYmplY3QpIikKICBjbyA9IGFzLm1hdHJpeChjb21ibih1bmlxdWUoZmFjdG9ycyksMikpCiAgcGFpcnMgPSBjKCkKICBGLk1vZGVsID1jKCkKICBSMiA9IGMoKQogIHAudmFsdWUgPSBjKCkKICAKICAKICAKICBmb3IoZWxlbSBpbiAxOm5jb2woY28pKXsKICAgIHN1Yl9pbmRzIDwtIGZhY3RvcnMgJWluJSBjKGFzLmNoYXJhY3Rlcihjb1sxLGVsZW1dKSxhcy5jaGFyYWN0ZXIoY29bMixlbGVtXSkpCiAgICByZXNwIDwtIGFzLm1hdHJpeCh4KVtzdWJfaW5kcyxzdWJfaW5kc10KICAgIGFkID0gYWRvbmlzMihhcy5kaXN0KHJlc3ApIH4KICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgIGZhY3RvcnNbc3ViX2luZHNdLCBzdHJhdGE9c3RyYXR1bVtzdWJfaW5kc10sIHBlcm11dGF0aW9ucz1wZXJtKTsKICAgIAogICAgcGFpcnMgPSBjKHBhaXJzLHBhc3RlKGNvWzEsZWxlbV0sJ3ZzJyxjb1syLGVsZW1dKSk7CiAgICBGLk1vZGVsID1jKEYuTW9kZWwsYWQkRlsxXSk7CiAgICBSMiA9IGMoUjIsYWQkUjJbMV0pOwogICAgcC52YWx1ZSA9IGMocC52YWx1ZSxhZCRgUHIoPkYpYFsxXSkKICAgIAogIH0KICAKICBwLmFkanVzdGVkID0gcC5hZGp1c3QocC52YWx1ZSxtZXRob2Q9cC5hZGp1c3QubSkKICBwYWlydy5yZXMgPSBkYXRhLmZyYW1lKHBhaXJzLEYuTW9kZWwsUjIscC52YWx1ZSxwLmFkanVzdGVkKQogIHJldHVybihwYWlydy5yZXMpCn0KYGBgCgpgYGB7cn0KIyBDYWxjdWxhdGUgZGlzdGFuY2UgbWF0cmljZXMKcHNfYmMgPC0gcGh5bG9zZXE6OmRpc3RhbmNlKHBzX29iamVjdCwgbWV0aG9kID0gImJyYXkiKQpwc19ldWMgPC0gcGh5bG9zZXE6OmRpc3RhbmNlKHBzX29iamVjdCwgbWV0aG9kID0gImV1Y2xpZGVhbiIpCmBgYAojIyMgUEVSTUFOT1ZBcwpQRVJNQU5PVkEncyB3aXRoIEFkb25pcyAtICBQZXJtdXRhdGlvbmFsIE11bHRpdmFyaWF0ZSBBbmFseXNpcyBvZiBWYXJpYW5jZS4gVGhpcyBtZWFzdXJlcyBkaXNzaW1pbGFyaXR5IGluIHJlc3BvbnNlIHRvIG9uZSBvciBtb3JlIGZhY3RvcnMgaW4gYW4gYW5hbHlzaXMgb2YgdmFyaWFuY2UgZGVzaWduLiBEaXNzaW1pbGFyaXR5IHN0YXRpc3RpY3MgYXJlIHVzZWQgdG8gbWVhc3VyZSBkaXN0YW5jZXMgYmV0d2VlbiBkYXRhIHBvaW50cyBhbmQgdGVzdCB3aGV0aGVyIHRoZXkgYXJlIHNpZ25pZmljYW50bHkgZGlmZmVyZW50LgoKV2UgcnVuIHRoZSBBZG9uaXMgdGVzdCBzcGVjaWZ5aW5nIHRoZSB0cmVhdG1lbnQgZ3JvdXBzIGluIHRoZSBtb2RlbCBmb3JtdWxhLiAKCiMjIyMgQnJheS1jdXJ0aXMKQnJheS1DdXJ0aXMgZGlzc2ltaWxhcml0eSBleGFtaW5lcyB0aGUgYWJ1bmRhbmNlcyBvZiBBU1ZzIHRoYXQgYXJlIHNoYXJlZCBiZXR3ZWVuIHR3byBzYW1wbGVzLCBhbmQgdGhlIG51bWJlciBvZiBBU1ZzIGZvdW5kIGluIGVhY2guIEJyYXktQ3VydGlzIGRpc3NpbWlsYXJpdHkgcmFuZ2VzIGZyb20gMC0xLiBJZiAwLCB0aGUgdHdvIHNhbXBsZXMgc2hhcmUgYWxsIHRoZSBzYW1lIEFTVnM7IGlmIDEsIHRoZXkgZG9u4oCZdCBzaGFyZSBhbnkgQVNWcy4KCiMjIyMgUGVybWFub3ZhIHJlc3VsdApUaGUgdmFsdWUgdW5kZXIgdGhlIGNvbHVtbiBsYWJlbGVkICdQcig+RiknIGluIHRoZSByZXN1bHRzIHRhYmxlIGluZGljYXRlcyBzaWduaWZpY2FuY2UgKGkuZS4gcC12YWx1ZSkKYGBge3J9CiNtYWtlIGEgZGF0YWZyYW1lIG91dCBvZiB0aGUgc2FtcGxlIGRhdGEKc2FtcGxlZGYgPC0gZGF0YS5mcmFtZShzYW1wbGVfZGF0YShwc19vYmplY3QpKQoKYWRvbmlzMihwc19iYyB+IHRyZWF0bWVudCwgZGF0YSA9IHNhbXBsZWRmKSAKYGBgCiMjIyMgRXVjbGlkZWFuCk1lYXN1cmVzIHRoZSBkaXN0YW5jZSBiZXR3ZWVuIHR3byBzYW1wbGVzIGluIEV1Y2xpZGVhbiBzcGFjZSAodGhlIGxlbmd0aCBvZiB0aGUgbGluZSBzZWdtZW50IGJldHdlZW4gdGhlbSkuCgojIyMjIFBlcm1hbm92YSByZXN1bHQKVGhlIHZhbHVlIHVuZGVyIHRoZSBjb2x1bW4gbGFiZWxlZCAnUHIoPkYpJyBpbiB0aGUgcmVzdWx0cyB0YWJsZSBpbmRpY2F0ZXMgc2lnbmlmaWNhbmNlIChpLmUuIHAtdmFsdWUpCmBgYHtyfQphZG9uaXMyKHBzX2V1YyB+IHRyZWF0bWVudCwgZGF0YSA9IHNhbXBsZWRmKSAKYGBgCgojIyMgUGFpcndpc2UgY29tcGFyaXNvbnMKQSBtdWx0aS1sZXZlbCBBZG9uaXMgdGVzdCB1c2luZyB0aGUgRkRSIG11bHRpcGxlIHRlc3QgY29ycmVjdGlvbi4gCgojIyMjIEJyYXktY3VydGlzIHBhaXJ3aXNlIHJlc3VsdApgYGB7cn0KcGFpcndpc2UuYWRvbmlzLmRtKHBzX2JjLCBzYW1wbGVkZiR0cmVhdG1lbnQsIHAuYWRqdXN0Lm0gPSAiZmRyIikKCmBgYAojIyMjIEV1Y2xpZGVhbiBwYWlyd2lzZSByZXN1bHQKYGBge3J9CnBhaXJ3aXNlLmFkb25pcy5kbShwc19ldWMsIHNhbXBsZWRmJHRyZWF0bWVudCwgcC5hZGp1c3QubSA9ICJmZHIiKSAKCmBgYAojIyMgQmV0YSBkaXZlcnNpeSBQQ29BIGFuZCBOTURTIHBsb3RzClBDb0EgYW5kIE5NRFMgcGxvdHMgYXJlIHVzZWQgdG8gdmlzdWFsaXplIHRoZSBzaW1pbGFyaXRpZXMvZGlzc2ltaWxhcml0aWVzIG9mIHNhbXBsZSBwb2ludHMgdXNpbmcgdGhlaXIgY2FsY3VsYXRlZCBkaXN0YW5jZS9kaXNzaW1pbGFyaXR5IG1hdHJpY2VzIChmcm9tIHRoZSBCcmF5LWN1cnRpcyBhbmQgRXVjbGlkZWFuIGRpc3RhbmNlIG1lYXN1cmVtZW50cykuIFNhbXBsZXMgdGhhdCBhcmUgY2xvc2VyIGFyZSBtb3JlIHJlbGF0ZWQgYW5kIHZpY2UgdmVyc2EuIApQQ29BIHBsb3RzIG1heGltaXplIHRoZSBsaW5lYXIgY29ycmVsYXRpb24gYmV0d2VlbiBzYW1wbGVzLCB3aGVyZWluIE5NRFMgcGxvdHMgbWF4aW1pemUgdGhlIHJhbmstb3JkZXIgY29ycmVsYXRpb24gYmV0d2VlbiBzYW1wbGVzLiBBZGRpdGlvbmFsbHksIGluIGNhc2Ugb2YgTk1EUywgZGF0YSBpcyBub3QgcmVxdWlyZWQgdG8gZml0IGEgbm9ybWFsIGRpc3RyaWJ1dGlvbi4KCkltYWdlcyBvZiBlYWNoIHBsb3QgY2FuIGJlIGZvdW5kIGluIHRoZSBzdGF0c19hbmFseXNpcy9iZXRhX2RpdmVyc2l0eV9wbG90cy8gZGlyZWN0b3J5LiAKCiMjIyMgQnJheS1jdXJ0aXMgUENvQQpgYGB7ciBCRF9icmF5LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuYWxpZ249ImNlbnRlciIsIHJlc3VsdHM9J2hpZGUnLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD04fQojIEJyYXktY3VydGlzCiNQQ09BIEJDCnBzX2JjX3Bjb2EgPC0gb3JkaW5hdGUocHNfb2JqZWN0LCBkaXN0YW5jZSA9IHBzX2JjLCAiUENvQSIpCgpwc19iY19wY29hX3Bsb3QgPC0gcGxvdF9vcmRpbmF0aW9uKHBzX29iamVjdCwgcHNfYmNfcGNvYSwgY29sb3IgPSAidHJlYXRtZW50IikgKyAKICBnZW9tX3BvaW50KHNpemUgPSAzKSArIAogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiM5NTQ1MzUiLCAiIzcwMjk2MyIsICIjRjI4QzI4IiwgIiMwODhGOEYiKSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQpwc19iY19wY29hX3Bsb3QKCiNzYXZlIGFzIHRpZmYKZ2dzYXZlKCJicmF5X3Bjb2FfcGxvdC50aWZmIiwgZHBpID0gMzAwLCBwbG90ID0gcHNfYmNfcGNvYV9wbG90LCBwYXRoID0gIi4vYmV0YV9kaXZlcnNpdHlfcGxvdHMvIikKYGBgCiMjIyMgQnJheS1jdXJ0aXMgTk1EUwpgYGB7ciBCRF9icmF5Miwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLmFsaWduPSJjZW50ZXIiLCByZXN1bHRzPSdoaWRlJywgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9OH0KI05NRFMgQkMKcHNfYmNfbm1kcyA8LSBvcmRpbmF0ZShwc19vYmplY3QsIGRpc3RhbmNlID0gcHNfYmMsICJOTURTIikKCnBzX2JjX25tZHNfcGxvdCA8LSBwbG90X29yZGluYXRpb24ocHNfb2JqZWN0LCBwc19iY19ubWRzLCBjb2xvciA9ICJ0cmVhdG1lbnQiKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsgCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiIzk1NDUzNSIsICIjNzAyOTYzIiwgIiNGMjhDMjgiLCAiIzA4OEY4RiIpKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCnBzX2JjX25tZHNfcGxvdAoKI3NhdmUgYXMgdGlmZgpnZ3NhdmUoImJyYXlfbm1kc19wbG90LnRpZmYiLCBkcGkgPSAzMDAsIHBsb3QgPSBwc19iY19ubWRzX3Bsb3QsIHBhdGggPSAiLi9iZXRhX2RpdmVyc2l0eV9wbG90cy8iKQpgYGAKIyMjIyBFdWNsaWRlYW4gUENvQQpgYGB7ciBCRF9ldWMsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy5hbGlnbj0iY2VudGVyIiwgcmVzdWx0cz0naGlkZScsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTh9CgojIEV1Y2xpZGVhbgojUENPQSBFVUMKcHNfZXVjX3Bjb2EgPC0gb3JkaW5hdGUocHNfb2JqZWN0LCBkaXN0YW5jZSA9IHBzX2V1YywgIlBDb0EiKQoKcHNfZXVjX3Bjb2FfcGxvdCA8LSBwbG90X29yZGluYXRpb24ocHNfb2JqZWN0LCBwc19ldWNfcGNvYSwgY29sb3IgPSAidHJlYXRtZW50IikgKyAKICBnZW9tX3BvaW50KHNpemUgPSAzKSArIAogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiM5NTQ1MzUiLCAiIzcwMjk2MyIsICIjRjI4QzI4IiwgIiMwODhGOEYiKSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQpwc19ldWNfcGNvYV9wbG90Cgojc2F2ZSBhcyB0aWZmCmdnc2F2ZSgiZXVjX3Bjb2FfcGxvdC50aWZmIiwgZHBpID0gMzAwLCBwbG90ID0gcHNfZXVjX3Bjb2FfcGxvdCwgcGF0aCA9ICIuL2JldGFfZGl2ZXJzaXR5X3Bsb3RzLyIpCmBgYAojIyMjIEV1Y2xpZGVhbiBOTURTCmBgYHtyIEJEX2V1YzIsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy5hbGlnbj0iY2VudGVyIiwgcmVzdWx0cz0naGlkZScsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTh9CiNOTURTIEJDCnBzX2V1Y19ubWRzIDwtIG9yZGluYXRlKHBzX29iamVjdCwgZGlzdGFuY2UgPSBwc19ldWMsICJOTURTIikKCnBzX2V1Y19ubWRzX3Bsb3QgPC0gcGxvdF9vcmRpbmF0aW9uKHBzX29iamVjdCwgcHNfZXVjX25tZHMsIGNvbG9yID0gInRyZWF0bWVudCIpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMykgKyAKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjOTU0NTM1IiwgIiM3MDI5NjMiLCAiI0YyOEMyOCIsICIjMDg4RjhGIikpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKcHNfZXVjX25tZHNfcGxvdAoKI3NhdmUgYXMgdGlmZgpnZ3NhdmUoImV1Y19ubWRzX3Bsb3QudGlmZiIsIGRwaSA9IDMwMCwgcGxvdCA9IHBzX2V1Y19ubWRzX3Bsb3QsIHBhdGggPSAiLi9iZXRhX2RpdmVyc2l0eV9wbG90cy8iKQpgYGAKCiMjIFJlbGF0aXZlIEFidW5kYW5jZSBUYXhhIFBsb3RzCiMjIyBSZWxhdGl2ZSBhYnVuZGFuY2UgdGF4YSBiYXIgcGxvdHMgZm9yIHRyZWF0bWVudApQbG90cyB3ZXJlIG1hZGUgYXQgdGhlIHBoeWx1bSwgZ2VudXMsIGFuZCBzcGVjaWVzIGxldmVsLCBjb21wYXJpbmcgYWNyb3NzIHRoZSA0IHRyZWF0bWVudHMuICAKCkltYWdlcyBvZiBlYWNoIHBsb3QgY2FuIGJlIGZvdW5kIGluIHRoZSBzdGF0c19hbmFseXNpcy90YXhhcGxvdHMvIGRpcmVjdG9yeS4gCgojIyMjIFBoeWx1bQpgYGB7ciBUYXhhcGxvdHNfcGh5LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuYWxpZ249ImNlbnRlciIsIHJlc3VsdHM9J2hpZGUnLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD03fQojIHRyYW5zZm9ybSB0byByZWxhdGl2ZSBhYnVuZGFuY2UKcHNfcmVsIDwtIHRyYW5zZm9ybShwc19vYmplY3QsICJjb21wb3NpdGlvbmFsIikKCiMgbWVsdCB0aGUgZGF0YSBpbnRvIGEgdGFibGUKcHNfcmVsX21lbHQ8LSBwc19yZWwgJT4lCiAgcHNtZWx0KCkKCiMgR2V0IHBoeWx1bSB3aXRoIG1lYW4gcmVsYXRpdmUgYWJ1bmRhbmNlIGFjcm9zcyBhbGwgc2FtcGxlcyAKcHNfcmVsX3BoeWx1bV9zdW0gPC0gcHNfcmVsX21lbHQlPiUgZ3JvdXBfYnkoUmFuazMpICU+JSBkcGx5cjo6c3VtbWFyaXNlKEF2ZXIgPSBtZWFuKEFidW5kYW5jZSkpCm5hbWVzX3BzX3JlbF9waHlsdW0gPC0gcHNfcmVsX3BoeWx1bV9zdW0kUmFuazMKbmFtZXNfcHNfcmVsX3BoeWx1bQoKI1BoeWx1bSBQbG90CnRheGFwbG90X3BzX3JlbF9waHlsdW0gPSBnZ3Bsb3QocHNfcmVsX21lbHQKICAgICAgICAgICAgICAgICAgICAsIGFlcyh4ID0gdHJlYXRtZW50LCB5PUFidW5kYW5jZSkpICsgCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj0iZmlsbCIsIGFlcyhmaWxsID0gUmFuazMpKSAgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJhcXVhbWFyaW5lNCIsICJnb2xkIiwibGlnaHRwaW5rIiwgImZpcmVicmljayIsIiNEQTU3MjQiLCJpdm9yeTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJvcmNoaWQiLCAiI0NCRDU4OCIsICIjODU2OUQ1IiwgIiNEMTQyODUiLCAiIzY1MjkyNiIsImdyZXk4MCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiM1RTczOEYiLCIjRDFBMzNEIiwgIiM4QTdDNjQiLCJsaWdodGdyZWVuIiwiYXF1YW1hcmluZTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJhcXVhbWFyaW5lMiIsICJsaWdodHNhbG1vbiIsICIjQ0Q5QkNEIikpICsKICB0aGVtZV9idygpICsKICB5bGFiKCJSZWxhdGl2ZSBBYnVuZGFuY2UiKSArIHhsYWIoIlRyZWF0bWVudCIpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3Q9MC41LCBoanVzdD0wKSkKdGF4YXBsb3RfcHNfcmVsX3BoeWx1bSA8LSB0YXhhcGxvdF9wc19yZWxfcGh5bHVtICsgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJQaHlsdW0iKSkKdGF4YXBsb3RfcHNfcmVsX3BoeWx1bQoKZ2dzYXZlKCJ0YXhhcGxvdF9waHlsdW0udGlmZiIsIGRwaSA9IDMwMCwgcGxvdCA9IHRheGFwbG90X3BzX3JlbF9waHlsdW0sIHBhdGggPSAiLi90YXhhcGxvdHMvIikKYGBgCiMjIyMgR2VudXMKR2VuZXJhIHdpdGggYSByZWxhdGl2ZSBhYnVuZGFuY2UgbG93ZXIgdGhhbiAwLjAwMDEgd2VyZSBncm91cGVkIHRvZ2V0aGVyLgpgYGB7ciBUYXhhcGxvdHNfZ2VuLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuYWxpZ249ImNlbnRlciIsIHJlc3VsdHM9J2hpZGUnLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD03fQoKI0dldCBnZW5lcmEgd2l0aCBtZWFuIHJlYWx0aXZlIGFidW5kYW5jZSA+MC4wMDAxIGFjcm9zcyBhbGwgc2FtcGxlcyAKcHNfcmVsX2dlbnVzX3N1bSA8LSBwc19yZWxfbWVsdCU+JSBncm91cF9ieShSYW5rNykgJT4lIGRwbHlyOjpzdW1tYXJpc2UoQXZlciA9IG1lYW4oQWJ1bmRhbmNlKSkKcHNfcmVsX2dlbnVzX3N1YiA8LSBwc19yZWxfZ2VudXNfc3VtW3doaWNoKHBzX3JlbF9nZW51c19zdW0kQXZlciA+IDAuMDAwMSksXQpuYW1lc19wc19yZWxfZ2VudXMgPC0gcHNfcmVsX2dlbnVzX3N1YiRSYW5rNwpuYW1lc19wc19yZWxfZ2VudXMKCiMgUmVwbGFjZSBnZW5lcmEgd2l0aCA8MC4wMDEgYWJ1bmRhbmNlIHdpdGggIk5BIgpwc19yZWxfbWVsdCRSYW5rN1twc19yZWxfbWVsdCRSYW5rNyAhPSAiQWJpb3Ryb3BoaWEiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazcgIT0gIkFlcm9jb2NjdXMiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazcgIT0gIkRpYWxpc3RlciIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rNyAhPSAiR3JhbnVsaWNhdGVsbGEiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazcgIT0gIklnbmF2aWJhY3Rlcml1bSIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rNyAhPSAiTGFjdGljYXNlaWJhY2lsbHVzIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms3ICE9ICJMYWN0aWNhc2VpYmFjaWxsdXMiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazcgIT0gIkxhY3RpcGxhbnRpYmFjaWxsdXMiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazcgIT0gIkxhY3RvYmFjaWxsdXMiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazcgIT0gIkxhbmNlZmllbGRlbGxhIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms3ICE9ICJMZW50aWxhY3RvYmFjaWxsdXMiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazcgIT0gIkxldmlsYWN0b2JhY2lsbHVzIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms3ICE9ICJMaW1vc2lsYWN0b2JhY2lsbHVzIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms3ICE9ICJNZWdhc3BoYWVyYSIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rNyAhPSAiTW9yeWVsbGEiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazcgIT0gIlNodXR0bGV3b3J0aGlhIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms3ICE9ICJTb2xvYmFjdGVyaXVtIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms3ICE9ICJTdGFwaHlsb2NvY2N1cyIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rNyAhPSAiU3RyZXB0b2NvY2N1cyIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rNyAhPSAiVmVpbGxvbmVsbGEiXSA8LSBOQQoKI3JlcGxhY2UgTkEgd2l0aCAiUmVsLiBBYnVuZC48MC4wMDAxIgpwc19yZWxfbWVsdFtpcy5uYShwc19yZWxfbWVsdCldPC0iUmVsLiBBYnVuZC48MC4wMDAxIgojR2VuZXJhIHBsb3QKdGF4YXBsb3RfcHNfcmVsX2dlbnVzID0gZ2dwbG90KHBzX3JlbF9tZWx0CiAgICAgICAgICAgICAgICAgICAgLCBhZXMoeCA9IHRyZWF0bWVudCwgeT1BYnVuZGFuY2UpKSArIAogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb249ImZpbGwiLCBhZXMoZmlsbCA9IFJhbms3KSkgICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiYXF1YW1hcmluZTQiLCAiZ29sZCIsImxpZ2h0cGluayIsICJmaXJlYnJpY2siLCIjREE1NzI0IiwiaXZvcnk0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAib3JjaGlkIiwgIiNDQkQ1ODgiLCAiIzg1NjlENSIsICIjRDE0Mjg1IiwgIiM2NTI5MjYiLCJncmV5ODAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjNUU3MzhGIiwiI0QxQTMzRCIsICIjOEE3QzY0IiwibGlnaHRncmVlbiIsImFxdWFtYXJpbmU0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYXF1YW1hcmluZTIiLCAibGlnaHRzYWxtb24iLCAiI0NEOUJDRCIpKSArCiAgdGhlbWVfYncoKSArCiAgeWxhYigiUmVsYXRpdmUgQWJ1bmRhbmNlIikgKyB4bGFiKCJUcmVhdG1lbnQiKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0PTAuNSwgaGp1c3Q9MCkpCnRheGFwbG90X3BzX3JlbF9nZW51cyA8LSB0YXhhcGxvdF9wc19yZWxfZ2VudXMgKyBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9IkdlbnVzIikpCnRheGFwbG90X3BzX3JlbF9nZW51cwpnZ3NhdmUoInRheGFwbG90X2dlbnVzLnRpZmYiLCBkcGkgPSAzMDAsIHBsb3QgPSB0YXhhcGxvdF9wc19yZWxfZ2VudXMsIHBhdGggPSAiLi90YXhhcGxvdHMvIikKYGBgCiMjIyMgU3BlY2llcwpTcGVjaWVzIHdpdGggYSByZWxhdGl2ZSBhYnVuZGFuY2UgbG93ZXIgdGhhbiAwLjAxIHdlcmUgZ3JvdXBlZCB0b2dldGhlci4KYGBge3IgVGF4YXBsb3RzX3NwLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuYWxpZ249ImNlbnRlciIsIHJlc3VsdHM9J2hpZGUnLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD03fQojR2V0IHNwZWNpZXMgd2l0aCBtZWFuIHJlYWx0aXZlIGFidW5kYW5jZSA+MC4wMSBhY3Jvc3MgYWxsIHNhbXBsZXMgCnBzX3JlbF9zcGVjaWVzX3N1bSA8LSBwc19yZWxfbWVsdCU+JSBncm91cF9ieShSYW5rOSkgJT4lIGRwbHlyOjpzdW1tYXJpc2UoQXZlciA9IG1lYW4oQWJ1bmRhbmNlKSkKcHNfcmVsX3NwZWNpZXNfc3ViIDwtIHBzX3JlbF9zcGVjaWVzX3N1bVt3aGljaChwc19yZWxfc3BlY2llc19zdW0kQXZlciA+IDAuMDEpLF0KbmFtZXNfcHNfcmVsX3NwZWNpZXMgPC0gcHNfcmVsX3NwZWNpZXNfc3ViJFJhbms5Cm5hbWVzX3BzX3JlbF9zcGVjaWVzCgojIFJlcGxhY2UgZ2VuZXJhIHdpdGggPDAuMDAxIGFidW5kYW5jZSB3aXRoICJOQSIKIyBSZXBsYWNlIGdlbmVyYSB3aXRoIDwwLjAwMSBhYnVuZGFuY2Ugd2l0aCAiTkEiCnBzX3JlbF9tZWx0JFJhbms5W3BzX3JlbF9tZWx0JFJhbms5ICE9ICJMYWN0b2JhY2lsbHVzIGNyaXNwYXR1cyIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rOSAhPSAiTGFjdG9iYWNpbGx1cyBqZW5zZW5paSIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rOSAhPSAiTGltb3NpbGFjdG9iYWNpbGx1cyBmZXJtZW50dW0iICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazkgIT0gIkxpbW9zaWxhY3RvYmFjaWxsdXMgdmFnaW5hbGlzIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms5ICE9ICJNZWdhc3BoYWVyYSBtaWNyb251Y2lmb3JtaXMiICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHNfcmVsX21lbHQkUmFuazkgIT0gIlN0cmVwdG9jb2NjdXMgYW5naW5vc3VzIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms5ICE9ICJTdHJlcHRvY29jY3VzIG11dGFucyIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rOSAhPSAiU3RyZXB0b2NvY2N1cyBzYWxpdmFyaXVzIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms5ICE9ICJTdHJlcHRvY29jY3VzIHZlc3RpYnVsYXJpcyIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rOSAhPSAiVmVpbGxvbmVsbGEgYXR5cGljYSIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICBwc19yZWxfbWVsdCRSYW5rOSAhPSAiVmVpbGxvbmVsbGEgZGlzcGFyIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms5ICE9ICJWZWlsbG9uZWxsYSBnZW5vbW9zcC4gUDEgb3JhbCBjbG9uZSBNQjVfUDE3IiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBzX3JlbF9tZWx0JFJhbms5ICE9ICJWZWlsbG9uZWxsYSBzcC4gb3JhbCB0YXhvbiAxNTgiXSA8LSBOQQoKI3JlcGxhY2UgTkEgd2l0aCAiUmVsLiBBYnVuZC48MC4wMSIKcHNfcmVsX21lbHRbaXMubmEocHNfcmVsX21lbHQpXTwtIlJlbC4gQWJ1bmQuPDAuMDEiCiNTcGVjaWVzIHBsb3QKdGF4YXBsb3RfcHNfcmVsX3NwZWNpZXMgPSBnZ3Bsb3QocHNfcmVsX21lbHQKICAgICAgICAgICAgICAgICAgICAsIGFlcyh4ID0gdHJlYXRtZW50LCB5PUFidW5kYW5jZSkpICsgCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj0iZmlsbCIsIGFlcyhmaWxsID0gUmFuazkpKSAgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJhcXVhbWFyaW5lNCIsICJnb2xkIiwibGlnaHRwaW5rIiwgImZpcmVicmljayIsIiNEQTU3MjQiLCJpdm9yeTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJvcmNoaWQiLCAiI0NCRDU4OCIsICIjODU2OUQ1IiwgIiNEMTQyODUiLCAiIzY1MjkyNiIsImdyZXk4MCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiM1RTczOEYiLCAiI0QxQTMzRCIpKSArCiAgdGhlbWVfYncoKSArCiAgeWxhYigiUmVsYXRpdmUgQWJ1bmRhbmNlIikgKyB4bGFiKCJUcmVhdG1lbnQiKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0PTAuNSwgaGp1c3Q9MCkpCnRheGFwbG90X3BzX3JlbF9zcGVjaWVzIDwtIHRheGFwbG90X3BzX3JlbF9zcGVjaWVzICsgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJTcGVjaWVzIikpCnRheGFwbG90X3BzX3JlbF9zcGVjaWVzCmdnc2F2ZSgidGF4YXBsb3Rfc3BlY2llcy50aWZmIiwgZHBpID0gMzAwLCBwbG90ID0gdGF4YXBsb3RfcHNfcmVsX3NwZWNpZXMsIHBhdGggPSAiLi90YXhhcGxvdHMvIikKCmBgYAoKIyMjIFJlbGF0aXZlIGFidW5kYW5jZSB0b3AgMTAgdGF4YSBiYXIgcGxvdHMgcGVyIHNhbXBsZQpQbG90cyB3ZXJlIG1hZGUgYXQgdGhlIHBoeWx1bSwgZ2VudXMsIGFuZCBzcGVjaWVzIGxldmVsLCBjb21wYXJpbmcgYWNyb3NzIGFsbCBzYW1wbGVzLiAgCgpJbWFnZXMgb2YgZWFjaCBwbG90IGNhbiBiZSBmb3VuZCBpbiB0aGUgc3RhdHNfYW5hbHlzaXMvdGF4YXBsb3RzLyBkaXJlY3RvcnkuIAoKIyMjIyBUb3AgMTAgUGh5bGEKYGBge3IgVGF4YXBsb3RzMiwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLmFsaWduPSJjZW50ZXIiLCByZXN1bHRzPSdoaWRlJywgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTh9IAojIHRyYW5zZm9ybSB0byByZWxhdGl2ZSBhYnVuZGFuY2UKcHNfcmVsIDwtIHRyYW5zZm9ybShwc19vYmplY3QsICJjb21wb3NpdGlvbmFsIikKCiNUb3AgMTAgUEhZTEEKI0dldCBwaHlsdW0gbGV2ZWwKcHNfcGh5bHVtIDwtIHRheF9nbG9tKHBzX3JlbCwgdGF4cmFuaz0gIlJhbmszIikKI0dldCB0b3AgMTAgcGh5bHVtCnBoeWx1bV90b3AxMCA8LSBuYW1lcyhzb3J0KHRheGFfc3Vtcyhwc19waHlsdW0pLCBkZWNyZWFzaW5nPVRSVUUpKVsxOjEwXQpwc19waHlsdW1fdG9wMTAgPC0gcHJ1bmVfdGF4YShwaHlsdW1fdG9wMTAsIHBzX3BoeWx1bSkKCiMgbWVsdCB0aGUgZGF0YSBpbnRvIGEgdGFibGUKcHNfcGh5bHVtX21lbHQ8LSBwc19waHlsdW1fdG9wMTAgJT4lCiAgcHNtZWx0KCkKCiMgUGxvdCB0b3AgMTAgcGh5bHVtIGJ5IHNhbXBsZQp0YXhhcGxvdF9wc190b3AxMF9waHlsdW0gPSBnZ3Bsb3QocHNfcGh5bHVtX21lbHQKICAgICAgICAgICAgICAgICAgICAsIGFlcyh4ID0gc2FtcGxlLCB5PUFidW5kYW5jZSkpICsgCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj0iZmlsbCIsIGFlcyhmaWxsID0gUmFuazMpKSAgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJhcXVhbWFyaW5lNCIsICJnb2xkIiwibGlnaHRwaW5rIiwgImZpcmVicmljayIsIiNEQTU3MjQiLCJpdm9yeTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJvcmNoaWQiLCAiI0NCRDU4OCIsICIjODU2OUQ1IiwgIiNEMTQyODUiKSkgKwogIHRoZW1lX2J3KCkgKwogIHlsYWIoIlJlbGF0aXZlIEFidW5kYW5jZSIpICsgeGxhYigiU2FtcGxlIikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdD0wLjUsIGhqdXN0PTApKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9OSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NykpCnRheGFwbG90X3BzX3RvcDEwX3BoeWx1bSA8LSB0YXhhcGxvdF9wc190b3AxMF9waHlsdW0gKyBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9IlRvcCAxMCBQaHlsYSIpKQp0YXhhcGxvdF9wc190b3AxMF9waHlsdW0KCmdnc2F2ZSgidGF4YXBsb3RfdG9wMTBfcGh5bHVtLnRpZmYiLCBkcGkgPSAzMDAsIHdpZHRoID0gMTgsIGhlaWdodCA9IDgsIHVuaXRzID0gImluIiwgcGxvdCA9IHRheGFwbG90X3BzX3RvcDEwX3BoeWx1bSwgcGF0aCA9ICIuL3RheGFwbG90cy8iKQpgYGAKIyMjIyBUb3AgMTAgR2VuZXJhCmBgYHtyIFRheGFwbG90c190b3BfZ2VuLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuYWxpZ249ImNlbnRlciIsIHJlc3VsdHM9J2hpZGUnLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xOH0KCiNUb3AgMTAgR0VORVJBCiNHZXQgZ2VudXMgbGV2ZWwKcHNfZ2VudXMgPC0gdGF4X2dsb20ocHNfcmVsLCB0YXhyYW5rPSAiUmFuazciKQojR2V0IHRvcCAxMCBnZW5lcmEKZ2VudXNfdG9wMTAgPC0gbmFtZXMoc29ydCh0YXhhX3N1bXMocHNfZ2VudXMpLCBkZWNyZWFzaW5nPVRSVUUpKVsxOjEwXQpwc19nZW51c190b3AxMCA8LSBwcnVuZV90YXhhKGdlbnVzX3RvcDEwLCBwc19nZW51cykKCiMgbWVsdCB0aGUgZGF0YSBpbnRvIGEgdGFibGUKcHNfZ2VudXNfbWVsdDwtIHBzX2dlbnVzX3RvcDEwICU+JQogIHBzbWVsdCgpCiNoZWFkKHBzX2dlbnVzX21lbHQpCgojIFBsb3QgdG9wIDEwIHBoeWx1bSBieSBzYW1wbGUKdGF4YXBsb3RfcHNfdG9wMTBfZ2VudXMgPSBnZ3Bsb3QocHNfZ2VudXNfbWVsdAogICAgICAgICAgICAgICAgICAgICwgYWVzKHggPSBzYW1wbGUsIHk9QWJ1bmRhbmNlKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uPSJmaWxsIiwgYWVzKGZpbGwgPSBSYW5rNykpICArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImFxdWFtYXJpbmU0IiwgImdvbGQzIiwibGlnaHRwaW5rIiwgImZpcmVicmljayIsIiNEQTU3MjQiLCJpdm9yeTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJvcmNoaWQiLCAiI0NCRDU4OCIsICIjODU2OUQ1IiwgIiNEMTQyODUiKSkgKwogIHRoZW1lX2J3KCkgKwogIHlsYWIoIlJlbGF0aXZlIEFidW5kYW5jZSIpICsgeGxhYigiU2FtcGxlIikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdD0wLjUsIGhqdXN0PTApKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9OSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NykpCnRheGFwbG90X3BzX3RvcDEwX2dlbnVzIDwtIHRheGFwbG90X3BzX3RvcDEwX2dlbnVzICsgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJUb3AgMTAgR2VuZXJhIikpCnRheGFwbG90X3BzX3RvcDEwX2dlbnVzCgpnZ3NhdmUoInRheGFwbG90X3RvcDEwX2dlbnVzLnRpZmYiLCBkcGkgPSAzMDAsIHdpZHRoID0gMTgsIGhlaWdodCA9IDgsIHVuaXRzID0gImluIiwgcGxvdCA9IHRheGFwbG90X3BzX3RvcDEwX2dlbnVzLCBwYXRoID0gIi4vdGF4YXBsb3RzLyIpCmBgYAojIyMjIFRvcCAxMCBTcGVjaWVzCmBgYHtyIFRheGFwbG90c190b3Bfc3AsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy5hbGlnbj0iY2VudGVyIiwgcmVzdWx0cz0naGlkZScsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTE4fQoKI1RvcCAxMCBTUEVDSUVTCiNHZXQgc3BlY2llcyBsZXZlbApwc19zcGVjaWVzIDwtIHRheF9nbG9tKHBzX3JlbCwgdGF4cmFuaz0gIlJhbms5IikKI0dldCB0b3AgMTAgZ2VuZXJhCnNwZWNpZXNfdG9wMTAgPC0gbmFtZXMoc29ydCh0YXhhX3N1bXMocHNfc3BlY2llcyksIGRlY3JlYXNpbmc9VFJVRSkpWzE6MTBdCnBzX3NwZWNpZXNfdG9wMTAgPC0gcHJ1bmVfdGF4YShzcGVjaWVzX3RvcDEwLCBwc19zcGVjaWVzKQoKIyBtZWx0IHRoZSBkYXRhIGludG8gYSB0YWJsZQpwc19zcGVjaWVzX21lbHQ8LSBwc19zcGVjaWVzX3RvcDEwICU+JQogIHBzbWVsdCgpCiNoZWFkKHBzX3NwZWNpZXNfbWVsdCkKCiMgUGxvdCB0b3AgMTAgcGh5bHVtIGJ5IHNhbXBsZQp0YXhhcGxvdF9wc190b3AxMF9zcGVjaWVzID0gZ2dwbG90KHBzX3NwZWNpZXNfbWVsdAogICAgICAgICAgICAgICAgICAgICwgYWVzKHggPSBzYW1wbGUsIHk9QWJ1bmRhbmNlKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uPSJmaWxsIiwgYWVzKGZpbGwgPSBSYW5rOSkpICArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImFxdWFtYXJpbmU0IiwgImdvbGQzIiwibGlnaHRwaW5rIiwgImZpcmVicmljayIsIiNEQTU3MjQiLCJpdm9yeTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJvcmNoaWQiLCAiI0NCRDU4OCIsICIjODU2OUQ1IiwgIiNEMTQyODUiKSkgKwogIHRoZW1lX2J3KCkgKwogIHlsYWIoIlJlbGF0aXZlIEFidW5kYW5jZSIpICsgeGxhYigiU2FtcGxlIikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdD0wLjUsIGhqdXN0PTApKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9OSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NykpCnRheGFwbG90X3BzX3RvcDEwX3NwZWNpZXMgPC0gdGF4YXBsb3RfcHNfdG9wMTBfc3BlY2llcyArIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZCh0aXRsZT0iVG9wIDEwIFNwZWNpZXMiKSkKdGF4YXBsb3RfcHNfdG9wMTBfc3BlY2llcwoKZ2dzYXZlKCJ0YXhhcGxvdF90b3AxMF9zcGVjaWVzLnRpZmYiLCBkcGkgPSAzMDAsIHdpZHRoID0gMTgsIGhlaWdodCA9IDgsIHVuaXRzID0gImluIiwgcGxvdCA9IHRheGFwbG90X3BzX3RvcDEwX3NwZWNpZXMsIHBhdGggPSAiLi90YXhhcGxvdHMvIikKCmBgYAo=